undo log通过记录数据修改前的旧值(如insert记主键、update记原值、delete记整行),在事务失败或rollback时执行反向操作,确保事务“全做或全不做”,从而实现原子性。

MySQL 的 Undo Log 是实现事务原子性和回滚能力的核心机制,它通过记录数据修改前的旧值(即“反向操作”),让事务在失败或显式执行 ROLLBACK 时能安全地恢复到事务开始前的一致状态。
Undo Log 如何保障原子性
原子性要求事务中的所有操作要么全部成功,要么全部不生效。Undo Log 在事务执行过程中持续记录每一条变更的“前镜像”(before image):
- INSERT 操作:记录新插入行的主键(或唯一标识),回滚时直接按主键删除该行;
- UPDATE 操作:记录被修改字段的原始值(或整行旧值),回滚时用旧值覆盖当前值;
- DELETE 操作:记录被删行的完整内容(包括主键和所有列),回滚时重新插入该行。
这些日志在事务提交前始终保留,确保即使系统崩溃,未提交事务的状态也可依据 Undo Log 撤销,从而满足原子性约束。
Undo Log 的物理存储与生命周期
在 InnoDB 中,Undo Log 并非写入独立文件,而是存放在 Undo Tablespace(可配置为独立文件或系统表空间的一部分)中,以段(segment)、区(extent)、页(page)组织:
- 每个事务从 Undo Log Segment 分配空间,按需追加日志页;
- 事务提交后,对应 Undo Log 不会立即清除,而是标记为“可清理”,由后台线程(purge thread)根据 MVCC 可见性规则异步回收;
- 只有当所有活跃事务(包括长事务)都不再需要该 Undo Log 版本时,它才会被真正释放。
回滚操作的具体执行流程
执行 ROLLBACK 或事务异常终止时,InnoDB 按照 Undo Log 中记录的逆序(LIFO)逐条应用反向操作:
- 定位该事务对应的 Undo Log 链(通过事务 ID 和 rollback segment header 关联);
- 从最新一条日志开始,读取类型(INSERT/UPDATE/DELETE)及原始数据;
- 对聚簇索引和二级索引分别执行逆操作(例如 UPDATE 回滚需同时更新聚簇索引记录和涉及的二级索引项);
- 释放事务持有的锁,并将事务状态置为已回滚。
整个过程在内存中完成,不依赖磁盘重放,因此回滚速度快,且不破坏其他事务的并发执行。
与 Redo Log 的协同关系
Undo Log 负责逻辑回退,Redo Log 负责物理重做——二者分工明确、缺一不可:
- Redo Log 确保已提交事务的持久性(crash safe),记录“做了什么”;
- Undo Log 支持未提交事务的回滚和 MVCC 多版本读,记录“原来是什么”;
- 两者都写入磁盘,但 Redo Log 是顺序写、强制刷盘(受
innodb_flush_log_at_trx_commit控制),Undo Log 则可缓冲写入,由 purge 机制批量管理。
这种设计使 MySQL 同时满足 ACID 中的原子性(A)、一致性(C)、隔离性(I)和持久性(D)。











