mysql中InnoDB存储引擎的事务回滚与日志恢复

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

事务回滚靠的是 undo log,不是 redo log

很多人误以为回滚是用

redo log
做的,其实完全相反:
undo log
才是事务回滚的核心依据。InnoDB 在执行
INSERT
UPDATE
DELETE
时,会先写入对应的
undo log
记录(比如把旧值存下来),这样
ROLLBACK
时就能按链表逆序还原数据。而
redo log
只负责崩溃后重做已提交但未刷盘的修改,跟回滚无关。

关键点:

undo log
存在
system tablespace
或独立的
undo tablespace
(MySQL 8.0+ 默认启用)中,不是内存结构
事务提交后,
undo log
不会立刻删除,而是标记为可回收,由
Purge Thread
异步清理
长事务会阻碍
Purge
,导致
undo log
持续增长,甚至撑爆
undo tablespace

崩溃恢复只依赖 redo log,不读 undo log

MySQL 启动时的崩溃恢复流程,只扫描

redo log
文件(如
ib_logfile0
),重放其中处于
PREPARE
或已
COMMIT
状态的事务。它根本不会去碰
undo log
—— 因为恢复的目标是让数据页状态与最后成功提交的事务一致,而不是“撤销”什么。

实际行为:

如果一个事务只写了
redo log
但没写
commit record
(比如掉电发生在
COMMIT
写入一半时),恢复时会被忽略(当作未提交)
如果事务有
COMMIT
标记,则其所有
redo log
记录都会被重放;即使此时
undo log
还没刷盘,也不影响恢复结果
innodb_fast_shutdown=0
会强制做一次完整 purge 和 checkpoint,减少恢复时间;设为
1
(默认)则跳过 purge,下次启动时可能多花几秒

如何确认 undo log 是否足够支撑回滚?

没有直接命令能“查看当前 undo log 容量剩余多少”,但可以通过几个关键指标判断是否濒临风险:

SELECT NAME, VALUE FROM performance_schema.global_status 
WHERE NAME IN ('Innodb_undo_tablespaces', 'Innodb_undo_logs', 'Innodb_purge_trx_id');

更实用的是监控活跃事务和历史列表长度:

查长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60;
看历史列表长度(反映未 purge 的 undo 量):
SHOW ENGINE INNODB STATUS\G
,搜索
HISTORY LIST
行,超过 10000 就该警惕
检查 undo 表空间大小:
SELECT FILE_NAME, FILE_SIZE, MAX_SIZE FROM information_schema.FILES WHERE FILE_TYPE='UNDO LOG';

显式回滚失败的常见原因

ROLLBACK
命令本身极少报错,但“看起来没回滚成功”往往是因为:

事务已经自动提交:例如客户端开启了
autocommit=1
,每条语句都是独立事务,
ROLLBACK
对它无效
执行了 DDL(如
ALTER TABLE
):InnoDB 会在 DDL 前隐式提交当前事务,后续
ROLLBACK
只能回滚 DDL 之后的操作
连接断开或超时:事务可能已被服务端自动回滚,但客户端没收到通知;可通过
SHOW PROCESSLIST
查看
Command
列是否为
Sleep
Time
超长
使用了
XA START
的分布式事务:必须用
XA ROLLBACK
,普通
ROLLBACK
不起作用

真正影响回滚可靠性的,从来不是日志格式或配置参数,而是事务生命周期管理——尤其是别让事务开着不动,也别在事务里调外部 HTTP 接口或等用户输入。这些细节比记住日志类型更容易出问题。

相关推荐