InnoDB通过undo日志实现事务回滚和MVCC,记录数据修改前旧值;Insert undo日志提交即释放,Update/DELETE undo日志需purge线程按Read View清理。

InnoDB 通过 undo 日志(undo log)实现事务回滚,同时支撑 MVCC(多版本并发控制)。 它不是简单地“撤销 SQL”,而是记录数据修改前的旧值,让事务能在需要时读到一致的快照,或在异常时恢复到修改前的状态。
undo 日志的核心作用
undo 日志本质是“反向操作记录”,主要干两件事:
- 支持事务回滚:当事务执行 ROLLBACK 或崩溃重启后需要回滚未提交事务时,InnoDB 用 undo 日志把已写入 buffer pool(但未刷盘)的数据页“倒退”到修改前的样子;
- 支撑 MVCC 读一致性:SELECT 查询不加锁时,会根据事务的 Read View,结合 undo 链找到对应版本的行数据,实现非阻塞的快照读(如 REPEATABLE READ 隔离级别下看到事务开始时的数据状态)。
undo 日志怎么组织和存储
每条修改记录(INSERT/UPDATE/DELETE)都会生成对应的 undo 日志,按类型分两类:
- Insert undo log:只用于回滚 INSERT 操作,事务一提交就能立即释放(因为新插入的行对其他事务不可见,无需保留供 MVCC 使用);
- Update/DELETE undo log(也叫 Update undo log):用于回滚 UPDATE 和 DELETE,并且要长期保留,直到没有事务再需要它(比如所有活跃事务的 Read View 都不再依赖该版本),才能被 purge 线程清理。
这些日志存放在 red">undo tablespace(独立表空间,MySQL 5.6+ 默认启用)或系统表空间 ibdata1 中,以段(segment)、区(extent)、页(page)方式管理,每个 undo log segment 对应一个 rollback segment(回滚段),由 128 个 slot 组成,每个 slot 可分配给一个事务使用。
回滚具体怎么发生
回滚不是重放日志,而是“逆向应用”:
- INSERT 的 undo 记录包含主键值 → 回滚时直接按主键定位并删除该行;
- UPDATE 的 undo 记录保存修改前的整行旧值(或关键列)→ 回滚时用旧值覆盖当前值;
- DELETE 的 undo 记录保存整行数据 → 回滚时把这行重新插回去(逻辑上,实际可能标记为未删除)。
注意:回滚过程本身也写 redo 日志,确保回滚操作可持久、可恢复。
purge 和 undo 日志生命周期
undo 日志不会无限增长。Purge 线程负责清理已无用的 update undo log:
- 判断依据是全局最小活跃 Read View(即最老未提交事务的视图);
- 只有当某条 undo 记录的版本早于所有活跃事务的快照时,才允许被 purge;
- 如果长时间运行的大事务或未提交事务存在,会导致 undo 日志堆积、undo 表空间膨胀,甚至影响性能和磁盘空间。









