mysql事务日志实为redo log、undo log和binlog三类日志协同工作的机制:redo log保障已提交事务的持久性(wal+顺序写),undo log支撑回滚与mvcc,binlog仅用于复制和归档,无法替代前两者。

事务日志不是一种日志,而是三类日志协同工作的机制
MySQL 的“事务日志”常被误认为是单一组件,实际它指 redo log、undo log 和 binlog 三者在事务生命周期中各司其职的组合。其中前两者是 InnoDB 存储引擎原生实现的、保障 ACID 的核心日志;binlog 是 Server 层日志,不参与事务原子性或崩溃恢复,但承担复制与归档职责。真正支撑“事务”行为的,是 redo log 和 undo log —— 它们一个管“提交后不丢”,一个管“没提交就撤回”。
redo log 怎么保证事务持久性?关键在 WAL 和顺序写
redo log 的本质是物理日志:它不记录 SQL,而是记录“某个数据页(page)在某个偏移量上被改成了什么字节”。它的存在,是为了绕过“刷脏页”的高成本随机写,用小体积、顺序写的日志先落盘,实现 Write-Ahead Logging(WAL)。只要 redo log 写成功,即使 MySQL 崩溃,重启后也能从磁盘重放这些日志,把已提交但未刷盘的修改补上。
- 默认有两个文件:
ib_logfile0和ib_logfile1,循环复用 - 事务提交时,必须确保对应
redo log记录已 fsync 到磁盘(由innodb_flush_log_at_trx_commit控制,=1 是强持久性,=0 或 2 会牺牲部分安全性换性能) - 别试图手动解析
redo log文件——它是二进制格式、版本敏感、无公开文档,调试只能靠mysqlbinlog --base64-output=decode-rows -v配合崩溃恢复日志分析
undo log 不是“备份”,而是事务回滚和 MVCC 的底座
undo log 是逻辑日志:对每个 INSERT,它存一条对应的 DELETE;对每个 UPDATE,它存反向 UPDATE;对每个 DELETE,它存原始行。它不保证数据不丢,而是保证“能退回去”。更重要的是,InnoDB 的可重复读(RR)隔离级别依赖 undo log 构建快照——SELECT 不加锁时,会顺着事务 ID 回溯到对应版本的 undo log 链上取旧值。
-
undo log本身也要持久化,所以它的写入也会生成redo log(即 undo 的修改也得 crash-safe) - 长事务是
undo log的天敌:它会阻止 purge 线程清理旧版本,导致undo tablespace膨胀、历史版本堆积、甚至SELECT变慢(要遍历更长的版本链) - 不要混淆
ROLLBACK和TRUNCATE TABLE:后者不走undo log,不可回滚,且会重置自增计数器
为什么 binlog 不能替代 redo log 或 undo log?
binlog 是 Server 层日志,记录的是“逻辑操作”(如 UPDATE t SET x=2 WHERE id=1),它没有事务内部的页级变更信息,也没有回滚所需的历史版本。因此它无法用于崩溃恢复(缺少物理页上下文),也不能支撑 MVCC(没有行版本链)。它只适合做主从复制、按时间点恢复(PITR)或审计。
- 开启主从复制时,
binlog必须开启(log_bin=ON),而redo log和undo log是 InnoDB 自带、无法关闭的 -
binlog格式选ROW模式才能支持精确复制和闪回,但即便如此,它仍不能替代redo log的 crash recovery 能力 - 常见误操作:以为删了
binlog就等于清空所有历史——其实redo和undo还在,只是复制和 PITR 功能失效了
真正容易被忽略的,是三者生命周期的耦合关系:一个事务提交,要先后写 undo log → 写 redo log → 写 binlog(如果开启)→ 提交引擎事务 → 提交 binlog(两阶段提交)。任意一环失败,都可能引发主从不一致或恢复异常——这不是理论风险,而是线上 DBA 夜间被 call 的高频原因。










