“事务本身只是工作单位。ACID 事务性质说明希望这个单位具备哪些保证,调度与并发控制决定多个事务怎样交错,恢复算法决定崩溃后怎样兑现提交或中止。把这些机制塞进“事务”一词,会让接口无法说明自…”
形式陈述 ​
对一个 数据库事务,ACID 把四类保证分开陈述:
- 原子性(atomicity):事务要么以完整提交效果出现,要么中止且不留下该次尝试的逻辑效果;
- 一致性(consistency):若初态满足声明的不变量,事务程序正确、提交检查通过,则提交后的状态仍满足这些不变量;
- 隔离性(isolation):并发事务的可观察读写受某种明确的历史约束,例如可串行化或较弱的 SQL 隔离级别;
- 持久性(durability):系统确认提交后,即使发生承诺范围内的故障,恢复后的状态仍包含该提交。
四项的量词不同。原子性比较同一事务成功与中止的可见效果;一致性依赖业务不变量和程序前置;隔离性量化多个事务的交错历史;持久性则量化提交后的故障与恢复。它们不是一个名为“ACID”的单一开关。
若业务不变量写成
这只谈单个正确事务。并发执行还需隔离性保证组合历史能按声明方式还原成这些局部变换;否则两个分别保持
一致性尤其容易被误读。数据库可以检查外键、唯一性与显式 CHECK,却不知道“至少一名医生值班”或“总风险不超过额度”等未编码规则。即使系统完整提供 A、I、D,错误事务仍可能把一个合法状态原子地变成业务上错误的状态。
直觉
把事务想成穿过四道不同的门:原子性不让半件工作冒充成成功;一致性要求工作本身遵守规则;隔离性控制同时过门的人能看见什么;持久性保证已经盖章的结果不会因约定内故障消失。任一道门都不能替另一道验票。
工程文档若只写“支持 ACID”,信息仍然不够。需要继续问:隔离级别是什么,提交确认以哪个持久介质为准,电源故障和整机损坏是否都在保证内,外部副作用是否属于事务状态。这些限定决定了性质能否被验证。
四项也可能在不同接口边界成立。数据库内部写可原子回滚,不代表已经发给消息队列的通知会一起消失;单节点 commit 可持久,不代表异地灾备已经同步。先画出观察者和故障包络,再谈首字母缩写,才能避免把局部保证外推到整个业务链。
例子与边界
账户
这四句话需要不同证据。日志可以帮助撤销半次更新和重做已提交更新,却不能证明转账公式写对;串行化并发控制可以给出合法事务顺序,却不保证提交记录已经进入稳定存储。若应用在数据库提交后调用支付网关,网关扣款不在数据库状态里,单靠本地 ACID 也无法原子撤销远端动作。
持久性不是“数据永不丢失”。系统可能只承诺单机进程崩溃和断电恢复,不承诺介质毁坏、管理员误删或超过复制保留期的灾难。弱化隔离也不必破坏其他三项:一个 read committed 系统仍可原子并持久地提交事务,只是允许更多并发观察。
原子性也不等于每个物理字节瞬间变化。steal 策略可以让未提交页先落盘,只要恢复能撤销;no-force 可以让已提交页暂留内存,只要恢复能重做。ACID 约束崩溃前后可观察的逻辑结果,而不是禁止中间物理状态。
推论与应用
实现审查应把四项各自接到可检查的机制与测试:中止/故障注入验证原子性,约束与应用证明覆盖一致性,并发历史检查隔离性,稳定日志、刷盘顺序和重启测试覆盖持久性。测试一个成功路径不能替代四类证据。
预写日志常共同支撑原子性与持久性,锁和多版本协议常支撑隔离性,但这些只是实现路线。恢复算法若能在崩溃后得到某个一致物理页状态,仍须结合提交表判断哪些事务效果应保留;“恢复完成”不自动等于四项性质都成立。
一份可发布的 ACID 规格应附一张保证矩阵:正常并发、事务 abort、进程崩溃、断电、单盘损坏与区域丢失分别由谁处理,commit 返回前同步到哪里。矩阵中的空格是明确不保证,而不是让读者自行把“durable”扩成无限故障容忍。
参考资料
- Theo Härder and Andreas Reuter, “Principles of Transaction-Oriented Database Recovery,” ACM Computing Surveys 15(4), 1983, pp. 287–317。
- Jim Gray and Andreas Reuter, Transaction Processing: Concepts and Techniques, Morgan Kaufmann, 1992, Chs. 1–3。
- Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman, Concurrency Control and Recovery in Database Systems, Addison-Wesley, 1987, Ch. 1。