mysql undo log是什么_mysql事务回滚原理

来源:这里教程网 时间:2026-02-28 20:36:00 作者:

undo log
是 InnoDB 存储引擎为保证事务原子性和实现 MVCC(多版本并发控制)而生成的逻辑回滚日志。它不是“备份文件”,也不是“快照副本”,而是记录了每条
INSERT
UPDATE
DELETE
操作之前的数据状态,用于在事务失败或显式执行
ROLLBACK
时,把数据“逻辑还原”回去。


undo log 怎么被写入?什么时候开始记?

它在事务**第一条修改语句执行前就已启动记录**——不是等

COMMIT
ROLLBACK
才写,而是边改边记。

INSERT
:记录主键值,回滚时执行
DELETE
DELETE
:记录整行旧值,回滚时执行
INSERT
UPDATE
:记录被修改列的旧值 + 主键(或唯一标识),回滚时执行反向
UPDATE

注意:

SELECT
不产生 undo log;只有 DML 修改操作才触发。

它先写入内存中的

undo buffer
,再按需刷盘到
ibdata
或独立的
undo tablespace
(MySQL 8.0+ 默认启用)。


事务回滚时 undo log 真正怎么工作的?

回滚不是“从磁盘读旧数据再覆盖”,而是**按 undo log 链逆序执行逻辑反操作**:

事务 A 修改了 3 行,生成 3 条 undo log,按时间倒序连成链 执行
ROLLBACK
时,InnoDB 从链尾往前遍历,逐条“重放”对应的逆操作
比如某条 undo log 记着
UPDATE t SET x=100 WHERE id=5
→ 回滚时就做
UPDATE t SET x=旧值 WHERE id=5

整个过程不依赖外部备份,也不需要锁表;但要求 undo log 未被 purge 线程清理掉——所以长事务会阻塞 purge,导致

undo log
膨胀、空间无法回收。


常见配置和容易踩的坑

MySQL 8.0+ 中,

undo log
默认使用独立表空间,可通过以下参数控制行为:

innodb_undo_directory
:指定存放路径,默认是
datadir
,建议单独挂 SSD 目录
innodb_undo_tablespaces
:undo 表空间个数,影响并行 purge 效率
innodb_undo_log_truncate
:设为
1
才允许在线截断(收缩)过大的 undo 文件
innodb_max_undo_log_size
:单个 undo 表空间最大大小,超限后才触发 truncate(需配合上一项)

典型翻车场景:

开启
innodb_undo_log_truncate=0
(默认关闭),结果大事务跑完,undo 占满几十 GB 也无法自动缩容
innodb_undo_directory
指向 NFS 或慢盘,导致高并发更新时 undo 写入成为瓶颈
长时间不提交的事务(如应用端忘记
commit
),让 undo log 一直保留,MVCC 版本链拉长,拖慢其他查询性能

undo log 和 redo log、binlog 的关键区别在哪?

三者完全不是同一层的东西:

redo log
:物理日志,记录“页号+偏移+修改后字节”,用于崩溃恢复,保障持久性
undo log
:逻辑日志,记录“SQL 逆操作”,用于回滚和 MVCC,保障原子性与隔离性
binlog
:Server 层日志,记录逻辑 SQL 或行事件,用于主从复制和归档,不参与崩溃恢复

特别注意:

undo log
本身也受
redo log
保护——即 undo 的写入操作也会生成 redo,否则 undo 损坏就无法回滚了。


真正要管好 undo log,核心就三点:别让事务太长、别关

innodb_undo_log_truncate
、别把它和 redo/binlog 混为一谈。它不显眼,但一旦出问题,轻则慢查询,重则磁盘爆满、回滚卡死。

相关推荐