mysql怎么保证ACID
MySQL 的 ACID 特性主要通过 InnoDB 存储引擎的核心机制来保证,具体实现如下:
原子性 (Atomicity)
保证机制:Undo Log
原理:
事务开始前或修改数据时,InnoDB 会将被修改数据的旧版本(修改前的值) 记录到 Undo Log 中。
如果事务需要回滚(例如遇到错误或显式执行
ROLLBACK
),InnoDB 会利用 Undo Log 中的数据将修改过的数据恢复到事务开始前的状态。如果事务成功提交,相关的 Undo Log 记录并不会立即删除,而是在不再需要时(例如没有其他事务需要访问这些旧版本来保证一致性视图时)才被清理。
作用: 确保事务内的所有操作要么全部完成,要么全部不执行,没有中间状态。
一致性 (Consistency)
保证机制: 这是一个结果性的特性,由数据库的完整性约束(主键、外键、唯一索引、数据类型、NOT NULL等)以及应用程序的业务逻辑共同保证。原子性、隔离性、持久性是实现一致性的基础手段。
原理:
事务执行前,数据库处于一致状态。
事务执行过程中,数据库可能处于不一致的中间状态(这是允许的)。
事务执行完成后(无论提交还是回滚),数据库必须再次回到一致状态。
InnoDB 通过强制执行约束(如插入违反唯一索引会报错)和利用原子性、隔离性、持久性机制来确保事务结束时的一致性。
作用: 确保数据库从一个有效的状态转换到另一个有效的状态,不会破坏预定义的规则。
隔离性 (Isolation)
保证机制:锁机制 (Locking) 和 多版本并发控制 (MVCC - Multi-Version Concurrency Control)
原理:
锁机制 (Locking):
行级锁: InnoDB 默认使用行级锁(共享锁
S Lock
用于读,排他锁X Lock
用于写),大大减少了锁冲突,提高了并发度。表级锁 (意向锁): 在获取行锁之前,需要先获取表级的意向锁 (
IS Lock
/IX Lock
),用于快速判断表上是否有冲突的锁存在。锁的兼容性: 锁机制通过定义锁之间的兼容性(例如,多个事务可以同时持有同一行的共享锁
S Lock
,但一个事务持有排他锁X Lock
时,其他事务不能获得该行的任何锁)来隔离并发事务的读写操作。多版本并发控制 (MVCC):
这是 InnoDB 实现高并发读写的关键。
InnoDB 在修改数据行时,会为该行生成一个新版本(存储在表空间中),并保留旧版本(通过 Undo Log 链访问)。
每个事务启动时(或在执行第一个读操作时,取决于隔离级别),InnoDB 会为该事务生成一个一致性读视图 (
Read View
)。Read View
定义了该事务能看到哪些版本的数据行:能看到事务自身修改的数据。
能看到在
Read View
创建时已经提交的事务所做的修改。看不到在
Read View
创建时尚未提交的事务所做的修改。看不到在
Read View
创建之后才提交的事务所做的修改(在可重复读REPEATABLE READ
级别下通过读取符合其
Read View
的数据行版本(可能是最新版本,也可能是旧版本),不同事务可以在很大程度上避免读写冲突,实现非锁定读 (Consistent Nonlocking Reads
)。作用: 确保并发执行的事务之间互不干扰,每个事务感觉不到其他事务在同时执行。不同的隔离级别(读未提交
READ UNCOMMITTED
, 读已提交READ COMMITTED
, 可重复读REPEATABLE READ
, 串行化SERIALIZABLE
)通过调整锁的使用策略和Read View
的生成规则来实现不同程度的隔离性(以及并发性能)。持久性 (Durability)
保证机制:Redo Log 和 Double Write Buffer (部分场景)
原理:
Redo Log (重做日志):
这是持久性最核心的保证。
事务提交时,InnoDB 会先将事务产生的 Redo Log 记录(记录的是对数据页的物理修改)按顺序写入 Redo Log Buffer。
关键步骤: InnoDB 通过调用
fsync()
或类似机制,确保 Redo Log Buffer 中的内容强制刷新 (Force Log at Commit
) 到磁盘上的 Redo Log 文件中(通常是ib_logfile0
,ib_logfile1
)。只有这个刷盘操作完成,事务才被认为真正提交成功。即使此时修改的数据页本身还没有写回磁盘(脏页),数据库发生崩溃,重启后 InnoDB 可以根据 Redo Log 文件中的记录重放 (Redo) 所有已提交事务的修改,将数据恢复到崩溃前的状态。
Redo Log 是顺序写入的,比随机写入数据文件快得多,并且大小固定,循环使用(写满后覆盖最旧的日志)。
Double Write Buffer (双写缓冲区):
主要解决 Partial Page Write (部分页写入) 问题。
在将内存中修改过的脏数据页刷回磁盘上的数据文件之前,InnoDB 会先将这些页按顺序写入磁盘上一个共享表空间中的连续区域(Double Write Buffer)。
然后再将这些页写入它们在数据文件中的实际位置(可能是随机位置)。
如果在写入实际位置时发生崩溃(比如只写了一部分),重启恢复时,InnoDB 可以从 Double Write Buffer 中找到该页的一个完整副本,用它来覆盖损坏的页,然后再应用 Redo Log。这确保了数据页本身的完整性和一致性。
作用: 确保一旦事务成功提交,它对数据库所做的修改就是永久性的,即使发生系统崩溃、断电等故障,数据也不会丢失。
InnoDB 通过精心设计的 Undo Log、Redo Log、锁协议、MVCC 等机制协同工作,共同确保了 MySQL 数据库事务的 ACID 特性。