事务提交后数据真的不会丢吗?
会丢,但可以控制到“最多丢 1 个事务”——前提是
innodb_flush_log_at_trx_commit = 1且磁盘本身不掉电、不静默损坏。MySQL 的持久性不是靠“写完数据页”来保证的,而是靠
redo log落盘:只要事务提交时这条日志已同步写入磁盘,哪怕 MySQL 瞬间断电、进程崩溃,重启后也能把这行修改“重放”回来。
为什么改完数据不立刻刷盘,还能保证不丢?
因为 InnoDB 用的是预写式日志(WAL)机制:
事务修改 Buffer Pool 中的数据页 → 同时生成一条物理修改记录(比如“page 123 offset 48 处写入 4 字节 0x00000001”)→ 写入redo log buffer执行
COMMIT时,强制将该记录刷到磁盘上的
ib_logfile0等文件中 → 此时事务才算真正提交成功 数据页刷盘(
flush list)由后台线程异步完成,慢一点没关系,
redo log已经兜底
这个设计换来两个关键好处:顺序写日志比随机写数据页快得多;崩溃恢复时只需重放日志,不用扫描全库。
崩溃后 MySQL 是怎么“自己爬起来”的?
启动时自动触发崩溃恢复(crash recovery),全过程不依赖
binlog,纯靠
redo log: 读取
ib_logfile0和
ib_logfile1,定位到最近一次
checkpoint(由
innodb_checkpoint_lsn记录) 从 checkpoint 开始,逐条重放所有已
commit但尚未刷入数据文件的 redo 日志 如果遇到只有
prepare没有
commit的日志,则查
binlog:有完整对应事务就提交,没有就回滚(这是两阶段提交 2PC 的作用)
你不需要手动执行任何命令,只要 MySQL 能正常启动,这个过程就已在后台完成。
最容易被忽略的配置陷阱
很多线上库看似开了持久性,实则形同虚设,问题常出在这些地方:
innodb_flush_log_at_trx_commit = 2:日志只写进操作系统缓存,主机断电就丢 —— 这是默认值为 1 的最大“温柔陷阱”
sync_binlog = 0或
100:主从一致性或基于 binlog 的恢复可能失效,尤其在启用 GTID 时 RAID 卡/SSD 关闭了写缓存持久化(如未配 BBU 或 capacitor):
fsync命令实际没落盘,等于白设 误删或自动清理了
ib_logfile*:崩溃恢复直接失败,只能靠备份回退
验证是否生效最简单的方法:查变量
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';,必须是
1;再看错误日志里有没有 “InnoDB: Doing recovery” 字样 —— 那就是它真正在干活。
