关系数据库设计/事务性
ACID 是一个首字母缩略词,代表事务系统四个最理想的基本特性:事务应该是原子性的、一致性的、隔离的和持久的。
- 原子性 事务是指要么完全完成,要么对数据库不进行任何更改;即使在事务进行过程中出现错误或硬件故障,数据库也不会留下一个半完成的事务。
- 一致性 事务确保在事务完成后数据库处于一致状态,这意味着任何完整性约束(唯一键、外键、CHECK 约束等)都必须满足,否则事务将被拒绝。
- 隔离性 事务在处理过程中对数据库的其他用户是不可见的。
- 持久性 事务保证在调用方提交它们后不会回滚。
早期的关系型数据库管理系统无法始终保证其所有事务都满足这四个要求,但现代的关系型数据库管理系统通常可以提供 ACID 事务,即使在发生电源或硬件故障的情况下也是如此。
基本操作是读取和写入。然后是提交或中止。如果至少一项操作是对共享对象的写入,则会发生冲突。冲突被衡量为由两个不同事务执行的一对操作。因此,可能的组合是 RR、RW、WR、WW。
RW 会发生冲突,因为第一个 R 是一个不可重复读,因为来自另一个事务的 W 覆盖了 R 中读取的先前值。
在 WR 中,第一个 W 可能在 R 之后中止,导致级联中止,因为 W 写入的值已被中止,而 R 正在使用来自 W 的无效值。
在 WW 中,第一个写入是丢失更新,例如 W1W2R1 R1 丢失了更新,因为它读取了 W2
可以实现可序列化、可恢复的调度(两个事务的交错调度,与两个事务一个接一个的结果相同,并且一个事务的中止不会使另一个调度的提交无效)。
2PL - 两阶段锁定有一个增长阶段,在该阶段可以获取锁;当锁被释放时,所有锁都必须被释放,并且不能获取新的锁。这确保了一个事务可以使用在锁内获取的读操作来完成修改,而不会让另一个事务执行冲突的 RW、WR 或 WW。
锁提供独占访问;这与不可抢占性(锁只能由锁定事务/进程释放)、能够持有多个锁以及无法检测形成循环的锁链相结合,会导致死锁。
如果对锁持有者(例如年龄)应用了排序,则可以处理死锁,以防止循环发生。
基于锁的并发控制有时被称为悲观,而基于时间戳的并发控制被称为乐观,即悲观者预见到墨菲定律适用,因此会尽一切努力防止不良事件发生。锁定通常意味着至少阻止了一个写者-读者或写者-写者冲突,通过获取适当级别的锁,并通过增长阶段和释放阶段统一事务的多个更新或读取,在这个阶段,一旦释放一个锁,就不能获取其他锁。
乐观者通常像某部动画片中的小头猫一样,凭借着无畏的胆量和好运,大多数情况下都能完成事务,而无需事先检查。然而,作为一个合法的计算机算法,乐观的 timestamp 协议要求在提交时针对事务 timestamp 检查读取和写入的 timestamp,不需要写入 timestamp,有时甚至不需要在获取的数据项上进行读取 timestamp,这些数据项发生在事务 timestamp 之后(假设类似于单调的系统级时钟)。因此,一个受保护的乐观者最终可能会做很多工作,却因为反复中止而饿死,就像西西弗斯和他那块石头一样。
多版本并发控制 (MVCC) 是一种并发方法,它扩展了行级锁定,允许在不锁定行的前提下读取数据。在 MVCC 下,写入数据不会覆盖旧值,而只是创建一个新副本,并用写入数据的事务 ID 进行标记。这允许早期的只读事务继续读取旧值,这些值继续形成数据在被覆盖之前的一致快照。因此,早期的读取事务不需要在数据上持有锁。