mysql事务回滚靠undo log实现,它记录insert/update/delete的逻辑逆操作(如insert对应delete),回滚时倒序执行这些逆操作以保障原子性;undo log还支撑mvcc,通过版本链和read view提供一致性读。

MySQL 的 undo log 不是“备份文件”,也不是物理快照,它是 InnoDB 存储引擎生成的逻辑日志,核心作用就两个:让事务能回滚,让并发读不加锁。
undo log 怎么实现事务回滚(ROLLBACK)
事务执行过程中每条 INSERT、UPDATE、DELETE 操作,InnoDB 都会先在 undo log 中记录对应的逆操作逻辑:
-
INSERT→ 记录一条DELETE逻辑(含主键或唯一索引值) -
DELETE→ 记录一条INSERT逻辑(含完整旧行数据) -
UPDATE→ 记录一条反向UPDATE(把新值改回旧值)
注意:这些只是逻辑描述,undo log 不修改任何数据页本身。回滚时,InnoDB 按照事务 ID 和日志链表顺序重放这些逆操作,使上层看到“什么都没发生”——这正是原子性(Atomicity)的底层保障。
undo log 如何支撑 MVCC(非锁定一致性读)
当一个事务执行 SELECT(默认 REPEATABLE READ 隔离级别),而目标行正被其他未提交事务修改时,InnoDB 不会等锁,而是从 undo log 中查找该行的“历史版本”:
- 每个
undo log记录都带事务 ID 和 rollptr(指向更早版本的指针) - InnoDB 根据当前事务的
read view判断哪些版本可见 - 通过 rollptr 链式回溯,直到找到满足可见性规则的版本
这种机制让读写互不阻塞,但代价是:update undo log 必须保留到所有依赖它的事务结束(包括长事务),否则可能造成 Undo Log Truncation 失败或 purge 延迟,进而引发 ibdata1 持续膨胀。
insert undo log 和 update undo log 有什么区别
两类 undo log 的生命周期和清理策略完全不同:
-
insert undo log:只在事务内可见,事务一提交就能立即丢弃,不参与 purge -
update undo log(含UPDATE/DELETE):必须保留到没有事务再需要它做 MVCC 版本读,由后台purge thread异步清理
这意味着一个长时间运行的 SELECT(比如报表查询)会拖住 update undo log 清理,哪怕它本身没修改任何数据。这也是为什么线上禁止无限制的长事务。
undo log 存在哪?能手动删吗
默认情况下,undo log 存在 innodb_undo_tablespaces 指定的 undo 表空间中(如 undo_001、undo_002),而不是系统表空间 ibdata1 —— 这是 MySQL 5.7+ 的关键改进。
- 不能直接删除 undo 文件,否则会导致崩溃或数据不一致
- 可通过
SET GLOBAL innodb_undo_log_truncate = ON启用自动截断,配合innodb_max_undo_log_size控制单个 undo 表空间大小 - 真正释放磁盘空间需执行
ALTER UNDO TABLESPACE <name> SET INACTIVE</name>,再用DROP UNDO TABLESPACE(要求 MySQL 8.0.23+ 且启用innodb_undo_log_encrypt等前提)
最常被忽略的一点:即使设置了自动 truncate,若所有 undo 表空间都处于活跃状态(ACTIVE),也不会触发清理 —— 必须至少有一个 INACTIVE 表空间作为轮换缓冲。











