在MySQL的InnoDB存储引擎中,redo log和undo log是支持事务ACID特性的核心机制。它们通过不同的方式记录事务的修改,确保数据的可靠性、一致性以及崩溃恢复能力。以下是它们的详细介绍:
一. redo log(重做日志)
1.作用
- 持久性(Durability):确保事务提交后,修改的数据即使在系统崩溃或重启后也不会丢失。
- 崩溃恢复(Crash Recovery):当数据库异常关闭后,通过重放redo log中的记录,将未写入磁盘的已提交事务数据恢复到最新状态。
- 性能优化:通过**预写式日志(Write-Ahead Logging, WAL)**机制,减少直接写磁盘的随机IO压力。
2.特点
- 物理日志:记录的是数据页(Page)的物理修改(如页号、偏移量、具体值的变化),而非逻辑SQL语句。
- 顺序写入:redo log以顺序追加的方式写入磁盘(文件通常为
ib_logfile0
和ib_logfile1
),效率高。 - 循环覆盖:日志空间固定,写满后会覆盖旧日志。
- 与事务提交绑定:事务提交时,必须将redo log刷入磁盘(
innodb_flush_log_at_trx_commit=1
时强制刷盘)。
3.工作原理
- 写入顺序:事务执行过程中,InnoDB会先将数据页的修改记录到内存中的redo log buffer。
- 刷盘时机:事务提交时,redo log从buffer写入磁盘(具体由参数
innodb_flush_log_at_trx_commit
控制)。 - 崩溃恢复:
- 数据库启动时,如果发现脏页(内存中修改但未写入磁盘的数据页)未持久化,会通过redo log重放这些修改,恢复数据一致性。
- 例如:假设事务修改了某行数据但未刷盘,系统崩溃后重启,InnoDB会通过redo log将该修改应用到数据页。
4.示例
假设执行一条SQL语句:
UPDATE account SET balance = 1000 WHERE id = 1;
- redo log记录:数据页中
id=1
的balance
字段从旧值修改为1000的物理操作(如页号、偏移量、新值)。 - 作用:即使系统崩溃,重启后也能通过redo log恢复该修改。
二. undo log(回滚日志)
1.作用
- 原子性(Atomicity):事务回滚时,通过undo log将数据恢复到事务开始前的状态。
- 一致性(Consistency):配合多版本并发控制(MVCC),实现读写不阻塞,确保事务隔离性。
- 历史版本管理:记录数据修改前的旧值,用于生成快照(Snapshot),支持可重复读(Repeatable Read)隔离级别。
2.特点
- 逻辑日志:记录的是逆向操作(如
INSERT
对应DELETE
,UPDATE
对应反向UPDATE
)。 - 随机写入:存储于系统表空间的**回滚段(Rollback Segment)**中,可能涉及随机IO。
- 生命周期:
- 事务提交后,undo log不会立即删除,而是由Purge线程异步清理。
- 在MVCC中,未被读取事务引用的旧版本数据才会被清除。
3.工作原理
- 记录逆向操作:
- 在事务修改数据前,InnoDB会将旧值写入undo log。
- 例如:
UPDATE account SET balance = 1000 WHERE id = 1
时,undo log会记录balance=原值
。
- 事务回滚:
- 如果事务回滚,InnoDB会根据undo log中的逆向操作,将数据恢复到修改前的状态。
- MVCC支持:
- 通过undo log链表保存数据的多个版本,不同事务根据隔离级别读取对应的历史版本。
- 例如:事务A读取数据时,若其他事务B正在修改该数据,A会通过undo log获取数据修改前的版本,避免冲突。
4.示例
假设执行一条SQL语句:
UPDATE account SET balance = 1000 WHERE id = 1;
- undo log记录:
balance
字段的旧值(如500)及反向操作(如UPDATE account SET balance = 500 WHERE id = 1
)。 - 作用:
- 若事务回滚,通过undo log将
balance
恢复为500。 - 若其他事务需要读取该行数据的历史版本(如MVCC),通过undo log获取旧值。
- 若事务回滚,通过undo log将
三. redo log与undo log的协同
- 事务提交的两阶段提交:
- Prepare阶段:将事务的修改写入redo log(标记为
prepare
状态)。 - Commit阶段:将事务的修改写入binlog,再更新redo log为
commit
状态。
- 这确保了redo log和binlog的一致性,避免数据不一致问题。
- Prepare阶段:将事务的修改写入redo log(标记为
- 持久性保障:
- undo log的修改也会生成redo log,确保undo log本身在崩溃恢复后仍然可用。
- MVCC实现:
- undo log保存数据的历史版本,结合事务的隔离级别(如可重复读),提供一致性读。
四. redo log与undo log的区别
特性 | redo log | undo log |
---|---|---|
作用 | 保证事务的持久性(Durability) | 保证事务的原子性(Atomicity)和MVCC |
记录内容 | 物理日志(数据页的修改细节) | 逻辑日志(逆向操作) |
存储位置 | 独立文件(ib_logfile0 等) | 系统表空间的回滚段(Rollback Segment) |
写入方式 | 顺序写入(高效) | 随机写入 |
生命周期 | 事务提交后可能被覆盖(循环使用) | 事务提交后由Purge线程异步清理 |
与事务的关系 | 记录事务的修改,用于崩溃恢复 | 记录事务的旧值,用于回滚和MVCC |
五. 实际场景中的协作
以转账操作为例:
- 事务开始:
- 扣减账户A的余额(
balance -= 100
)。 - 增加账户B的余额(
balance += 100
)。
- 扣减账户A的余额(
- undo log记录:
- 记录账户A的旧余额(如1000)和反向操作(
balance += 100
)。 - 记录账户B的旧余额(如500)和反向操作(
balance -= 100
)。
- 记录账户A的旧余额(如1000)和反向操作(
- redo log记录:
- 记录账户A和账户B的数据页修改(物理操作)。
- 事务提交:
- redo log刷入磁盘,确保持久性。
- 崩溃恢复:
- 如果系统崩溃,重启后通过redo log恢复已提交的转账操作。
- 回滚操作:
- 如果事务失败,通过undo log将账户A和B的余额恢复到原始值。
六.总结
- redo log是物理日志,用于崩溃恢复和持久性,确保已提交事务的修改不丢失。
- undo log是逻辑日志,用于事务回滚和MVCC,保证原子性和一致性。
- 两者共同协作,支撑MySQL的ACID特性,是数据库可靠性和高性能的关键机制。