在 MySQL 的 InnoDB 存储引擎中,事务需要满足 ACID(原子性 Atomicity、一致性 Consistency、隔离性 Isolation、持久性 Durability)特性。
MySQL 主要通过 Undo Log、Redo Log、Binlog、MVCC、锁机制 等手段来实现 ACID。
1. 原子性(Atomicity)
原子性指的是事务中的所有操作要么全部成功,要么全部失败回滚。
如何实现原子性?
✅ 通过 Undo Log(撤销日志)
事务开始前,MySQL 记录修改前的数据快照到 Undo Log。
如果事务回滚,MySQL 使用 Undo Log 还原数据,恢复到事务前的状态。
示例
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
ROLLBACK; -- 触发原子性回滚
执行
ROLLBACK
时,Undo Log 用于恢复balance
的原始值。
原子性保证
如果事务失败(崩溃、错误等),Undo Log 确保数据可以回滚。
事务要么完全执行,要么完全回滚,不会导致部分更新的状态。
2. 一致性(Consistency)
一致性指的是事务执行后,数据库应从一个一致状态转换到另一个一致状态。
如何实现一致性?
✅ 通过数据库约束
主键约束(PRIMARY KEY)
唯一约束(UNIQUE)
外键约束(FOREIGN KEY)
非空约束(NOT NULL)
检查约束(CHECK)
✅ 通过 ACID 机制共同保障
原子性:事务失败时,Undo Log 确保数据回滚,避免数据异常。
隔离性:多个事务并发时,MVCC 和锁机制保证数据不冲突。
持久性:Redo Log 确保已提交的事务不会丢失。
示例
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
保证一致性的机制
事务提交前,不能让外部看到中间状态(事务隔离)。
事务提交后,所有更改必须是合法的(事务持久性)。
如果失败,则回滚所有操作,恢复到一致状态。
3. 隔离性(Isolation)
隔离性指的是多个事务并发执行时,互不干扰,避免脏读、不可重复读、幻读等问题。
如何实现隔离性?
✅ 通过事务隔离级别
✅ 通过 MVCC(多版本并发控制)
MVCC 通过 Undo Log 维护多个版本的数据快照,让事务可以读取历史数据,而不会被并发事务影响。
快照读(ReadView):在事务开始时获取一个一致性视图,让同一个事务内的所有查询看到相同的数据版本。
✅ 通过锁机制
共享锁(S 锁,Shared Lock):多个事务可以共享读,但不能修改。
排他锁(X 锁,Exclusive Lock):事务独占写,不允许其他事务读写。
间隙锁(Gap Lock):解决幻读,防止插入新数据。
示例
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 读取时创建 ReadView
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
隔离性保证:
事务在
SELECT
之后即使有其他事务更新balance
,事务内的balance
值不会变化。
4. 持久性(Durability)
持久性指的是事务提交后,数据必须永久保存,即使系统崩溃,数据也不会丢失。
如何实现持久性?
✅ 通过 Redo Log(重做日志)
事务执行时,先将变更写入 Redo Log,但不立即写入磁盘。
事务提交时,刷新 Redo Log 到磁盘,确保数据不会丢失。
系统崩溃时,使用 Redo Log 恢复数据,确保事务数据持久化。
✅ 通过 Binlog(归档日志)
MySQL 主从复制 依赖
Binlog
,确保事务提交后数据不会丢失。在崩溃恢复时,
Binlog
可以用来重放事务。
示例
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT; -- 事务提交,刷新 Redo Log
事务提交后,数据持久化到磁盘,确保不会丢失。
5. MySQL 事务 ACID 的实现总结
6. MySQL ACID 机制优化建议
✅ 提高事务持久性
SET GLOBAL innodb_flush_log_at_trx_commit = 1; -- 每次提交时刷新 Redo Log
SET GLOBAL sync_binlog = 1; -- 事务提交时同步写入 Binlog
✅ 优化事务隔离性
OLTP 业务:使用
READ COMMITTED
,避免间隙锁,提高并发能力。金融业务:使用
REPEATABLE READ
确保数据一致性。
✅ 减少 Undo Log 开销
避免长事务:长事务会导致
Undo Log
过大,占用大量存储。使用合适的事务隔离级别,避免不必要的锁等待。
✅ 优化数据一致性
避免隐式提交:某些 DDL 语句(如
ALTER TABLE
)会导致事务隐式提交,应注意事务边界。
7. 结论
MySQL 的事务 ACID 主要通过 日志(Undo Log、Redo Log、Binlog)、MVCC、事务隔离级别、锁机制 来实现:
原子性 依赖
Undo Log
,保证事务失败时数据回滚。一致性 依赖 ACID 机制和数据库约束,确保事务执行后数据库状态正确。
隔离性 依赖 MVCC + 锁机制,确保事务之间互不干扰。
持久性 依赖
Redo Log
和Binlog
,保证崩溃恢复能力。