面试知识库
进阶

undo-log与事务回滚#

一句话答案#

undo log 记录数据修改前的值,用于事务回滚(INSERT→DELETE)和 MVCC 版本链的快照读。

核心要点
日志所属层作用格式写入时机
redo logInnoDB 引擎层崩溃恢复(保证持久性)物理日志(记录数据页的物理修改)事务执行过程中持续写
undo logInnoDB 引擎层事务回滚 + MVCC 版本链逻辑日志(记录逆操作)事务执行过程中持续写
binlogMySQL Server 层主从复制 + 数据归档恢复逻辑日志(SQL语句或行变更)事务提交时一次性写

关键区别:

  • redo log 是循环写(固定大小,写满后从头覆盖),binlog 是追加写(可保留完整历史)
  • redo log 是 InnoDB 引擎私有,binlog 是 MySQL Server 层,所有引擎共享
  • redo log 用于实例恢复(宕机后恢复内存数据),binlog 用于数据恢复(时间点恢复)和主从同步
面试回答(2分钟版)

undo log 是 InnoDB 引擎层的逻辑日志,记录数据修改前的逆操作:INSERT 记一条 DELETE,UPDATE 记旧值。它有两个核心作用:第一是保证事务原子性,事务回滚时按 undo log 执行逆操作恢复原始数据;第二是支撑 MVCC,多个版本的 undo log 串成版本链,快照读通过 ReadView 沿版本链找到自己可见的数据版本,实现非锁定读。和 redo log 的区别在于:redo log 是物理日志用于崩溃恢复保证持久性,undo log 是逻辑日志用于回滚和多版本读保证原子性和隔离性。需要注意的是 undo log 不会在事务提交后立即删除,因为其他事务的快照读可能还需要访问这些旧版本,要等到没有活跃事务引用时才由 purge 线程清理。这也是长事务有害的原因——它会导致 undo log 持续堆积无法回收,占用大量存储空间。

追问与易错

追问方向:

  • “undo log 什么时候被清理?”→ 事务提交后不会立即清理,要等到没有任何活跃事务的 Read View 引用该版本时,由 InnoDB 的 purge 线程异步回收
  • “长事务为什么有害?”→ 长事务持有的 Read View 导致 undo log 版本链无法被 purge 清理,持续堆积占用大量存储;同时长时间持有行锁增加锁冲突和死锁概率
  • “undo log 和 MVCC 什么关系?”→ undo log 通过 roll_pointer 串成版本链,MVCC 的快照读沿版本链查找,结合 Read View 的可见性规则找到当前事务应该看到的数据版本,实现非锁定一致性读

易错点:

  • ❌ undo log 就是备份——是逻辑逆操作日志
  • ❌ 事务提交后 undo 立即删——其他事务可能还在读