Appearance
什么是 ACID?
ACID 是一组属性,确保数据库事务(即作为单个逻辑单元执行的一系列操作)即使在发生错误、断电或其他故障时也能可靠地处理。
| 属性 | 全称 | 含义 | 简单比喻 |
|---|---|---|---|
| A | 原子性 | 事务中的所有操作要么全部完成,要么全部不完成,不会停留在中间状态。如果任何部分失败,整个事务都会回滚到之前的状态。 | “全部或全不” 就像银行转账:从A账户扣款和向B账户汇款必须同时成功或同时失败,不能只扣款不汇款。 |
| C | 一致性 | 事务必须使数据库从一个一致状态转换到另一个一致状态。所有数据必须符合所有预定义的规则(如约束、触发器、级联等)。 | “遵守规则” 转账前后,两个账户的总金额必须保持不变(守恒定律)。数据库完整性约束永远不会被破坏。 |
| I | 隔离性 | 并发执行的事务彼此隔离。一个事务的中间状态不应该被其他事务看到,防止数据混乱。隔离级别可以调整以平衡性能和数据准确性。 | “互不干扰” 就像你在独立房间内考试,不会被其他人的答案干扰,也看不到别人未交卷的答案。 |
| D | 持久性 | 一旦事务提交成功,它对数据的修改就是永久性的。即使系统发生崩溃、断电,数据也不会丢失,通常通过预写日志等技术实现。 | “落袋为安” 就像你把钱存进银行保险库,即使银行停电,你的钱记录也在,不会消失。 |
深入解析每个属性
1. 原子性 (Atomicity)
- 核心:不可分割的工作单元。
- 实现机制:通常通过 事务日志 和 UNDO 日志 实现。系统会记录事务开始前的状态,如果事务失败,就利用这些日志“回滚”到之前的状态。
- 示例:删除一条记录及其所有关联子记录。如果删除子记录时失败,那么父记录的删除操作也会被撤销。
2. 一致性 (Consistency)
- 核心:逻辑上的正确性。这不仅由数据库系统保证,也需要应用层逻辑的配合。
- 实现机制:数据库通过主键、外键、唯一约束、数据类型检查、触发器等来强制数据一致性。原子性、隔离性和持久性是数据库为保持一致性所提供的工具。
- 示例:
A账户余额 >= 0是一个一致性规则。任何事务(如扣款)都不能导致余额为负。
3. 隔离性 (Isolation)
- 核心:处理并发问题。
- 问题:如果不隔离,会导致:
- 脏读:读到另一个未提交事务的中间数据。
- 不可重复读:同一事务内两次读取同一数据,结果不同(因为被其他事务修改并提交了)。
- 幻读:同一事务内两次查询同一条件,返回的记录数不同(因为其他事务插入或删除了符合条件的记录)。
- 实现机制:数据库通过锁机制或多版本并发控制 来实现不同级别的隔离。SQL标准定义了四个隔离级别(从低到高):
- 读未提交:可能发生脏读、不可重复读、幻读。
- 读已提交:防止脏读,但可能发生不可重复读和幻读(多数数据库的默认级别)。
- 可重复读:防止脏读和不可重复读,但可能发生幻读。
- 序列化:最高级别,完全隔离,事务如同串行执行,性能最低。
4. 持久性 (Durability)
- 核心:数据的永久保存。
- 实现机制:主要依靠 WAL 技术。在数据实际写入磁盘前,先将事务的所有修改操作记录到持久化的日志文件中。即使系统崩溃,重启后也可以根据日志重做已提交的事务。
- 示例:电商订单支付成功,订单状态变为“已支付”。即使数据库服务器在下一秒宕机,重启后这个状态也必须保持。
实际应用中的权衡
- 完全 ACID:传统关系型数据库(如 MySQL(InnoDB)、PostgreSQL、Oracle、SQL Server)是典型的 ACID 数据库,强调整致性和可靠性。
- BASE 理论:相比之下,许多 NoSQL 数据库(如 MongoDB、Cassandra)为了达到高可用性和可扩展性,往往会放宽 ACID 要求,特别是隔离性,遵循 BASE 理论:
- Basically Available:基本可用
- Soft state:软状态(状态可能有延迟)
- Eventual consistency:最终一致性
- 分布式数据库:在分布式环境中,完全实现 ACID(特别是强隔离性)会极大影响性能。因此出现了如 两阶段提交 等协议来协调分布式事务,但也很复杂。现代分布式数据库(如 Google Spanner、TiDB)则通过新技术(如原子钟、Paxos/Raft协议)来提供分布式ACID保证。
总结
ACID 是确保数据库事务可靠、安全的黄金准则:
- 原子性 让你不用担心事务部分失败。
- 一致性 确保你的数据永远符合业务规则。
- 隔离性 让你在高并发时数据也不混乱。
- 持久性 让你可以信任已提交的数据。
理解 ACID 是设计健壮应用、选择合适数据库和处理数据一致性问题的基础。