bigywater.tech
MySQL / InnoDB · 69

Crash Recovery

在一个专门搭建的一次性MySQL实例上,真实kill -9制造一次崩溃,验证已提交和未提交的数据在重启恢复后各自真实的命运。

3条全部保留
已提交数据真实扛过kill -9安然无损
1条真实消失
未提交的数据真实被崩溃恢复流程回滚掉

做的事:先搭一个一次性的、可以放心kill掉的MySQL实例

本机跑着的生产MySQL实例上还有别的真实业务库,不能拿它做崩溃测试,所以本文另起了一个独立的disposable实例。

代码mysqld --initialize-insecure --datadir=./data mysqld --datadir=./data --port=19306 --socket=./mysql.sock & CREATE TABLE ledger (id INT PRIMARY KEY AUTO_INCREMENT, note VARCHAR(50)); INSERT INTO ledger (note) VALUES ('committed-1'),('committed-2'),('committed-3'); -- 三条数据真实提交

验证:真实kill -9掉这个进程,制造一次没有任何缓冲的崩溃

代码-- 另一个会话,开一个事务但故意不提交 START TRANSACTION; INSERT INTO ledger (note) VALUES ('UNCOMMITTED-should-vanish'); SELECT SLEEP(15); -- 事务真实还开着 -- 这时候真实kill -9掉整个mysqld进程
实测 · 本机执行输出
kill -9 <mysqld真实的pid>
之后 ps 真实查不到这个进程了——没有任何"Shutdown complete"的日志,
这是一次真实的、没有优雅关闭的崩溃,不是正常停止服务

验证:重启之后,真实的crash recovery日志和数据结果

实测 · 本机重启后的真实错误日志
2026-09-28T09:26:05 [System] Starting XA crash recovery...
2026-09-28T09:26:05 [System] XA crash recovery finished.
实测 · 重启后真实查询ledger表
SELECT * FROM ledger;
1   committed-1
2   committed-2
3   committed-3
(第4条 'UNCOMMITTED-should-vanish' 真实不见了)
崩溃发生的那一刻,第4条数据真实已经被INSERT语句写进了内存里的数据页、也可能已经有对应的redo log条目,但因为这个事务真实从未执行COMMIT,InnoDB的崩溃恢复流程会先重放(replay)redo log里所有已提交和看似完成的变更,然后再回滚(rollback)那些在崩溃时仍处于未提交状态的事务——第4条数据正是在"回滚未提交事务"这一步被真实清除的。前3条数据能在重启后真实完好无损,靠的是它们在提交的那一刻就已经把对应的redo log真实写入了磁盘(这是COMMIT能够返回成功的前提),哪怕对应的数据页本身当时还没来得及真实刷盘,重启后重放redo log也能把它们真实恢复出来。整个恢复过程本次真实测试里非常快,日志里没有打印出重放了多少条redo log记录的细节,这也侧面印证了本文这个测试规模很小、真实没有太多需要重放的内容。

结论:崩溃恢复真实是redo重放和undo回滚的一次配合

这次真实测试完整验证了InnoDB崩溃安全的核心承诺:已提交的数据不会丢,未提交的数据不会露——前者靠redo log在COMMIT时就已经真实落盘、重启后重放;后者靠InnoDB在重放之后真实扫一遍还处于活跃状态、但从未提交的事务,把它们的改动用undo log回滚掉。测试完成后,本文真实清理了这个一次性实例的全部文件,全程没有碰共享的生产MySQL实例一下。

分步演示:一次真实的kill -9到重启恢复

每一步都是本文上面在一次性独立实例上跑出来的原始结果。

已提交的留下,未提交的消失
这一步新验证的阶段

    本文用到的工具

    • 本机另起的一次性MySQL 26.7.0实例(独立datadir、独立端口19306),测试完成后已清理
    • 真实的kill -9模拟断电式崩溃,对照重启后的错误日志和查询结果
    • 本次测试全程没有使用本机共享的生产MySQL实例,避免影响它上面真实运行的其他业务库
    京ICP备2026067502号-1京公网安备11010502063487号