undo log 回滚原理
MySQL 的 Undo Log(回滚日志)是实现事务回滚和多版本并发控制(MVCC)的核心机制。它记录了事务对数据修改前的原始状态,确保事务可以按需回滚到之前的状态。以下是 Undo Log 实现事务回滚的详细流程和原理:
1. Undo Log 的作用
- 事务回滚:回滚未提交事务的修改。
- MVCC:提供历史数据版本,支持非锁定读(如
SELECT
查询读取快照)。 - 崩溃恢复:辅助恢复未提交事务的修改。
2. Undo Log 的结构
每条 Undo Log 记录包含以下关键信息:
- 事务 ID(TRX_ID):标识生成该记录的事务。
- 回滚指针(ROLL_PTR):指向更早版本的 Undo Log 记录,形成版本链。
- 修改前的数据镜像:被修改前的数据值(旧值)。
- 操作类型:标识操作是
INSERT
、UPDATE
还是DELETE
。
不同类型的 Undo Log
操作类型 | Undo Log 内容 | 回滚行为 |
---|---|---|
INSERT | 记录新插入行的主键值。 | 回滚时根据主键删除该行。 |
UPDATE | 记录被修改前的旧值(包括所有字段)。 | 回滚时将数据恢复为旧值。 |
DELETE | 记录被删除行的完整内容(所有字段值)。 | 回滚时重新插入该行。 |
3. 事务回滚的流程
步骤 1:生成 Undo Log
- 事务执行
INSERT
/UPDATE
/DELETE
操作时,InnoDB 会先写 Undo Log,再修改内存中的数据页。 - 例如:
修改前,Undo Log 会记录UPDATE users SET name = 'Alice' WHERE id = 1;
id=1
的原值(如name='Bob'
)。
步骤 2:构建版本链
- 同一行数据的多次修改会形成 Undo Log 版本链,通过
ROLL_PTR
指针串联。当前行数据 → Undo Log 1(最新修改) → Undo Log 2(更早修改) → ...
步骤 3:触发回滚
- 当事务执行
ROLLBACK
或因异常终止时,InnoDB 会根据事务 ID 找到其所有 Undo Log 记录。 - 逆向应用 Undo Log:从最新操作开始,按操作逆序执行回滚:
- 如果是
UPDATE
,将数据恢复为旧值。 - 如果是
DELETE
,重新插入被删除的行。 - 如果是
INSERT
,删除新插入的行。
- 如果是
步骤 4:清理 Undo Log
- 已提交事务的 Undo Log 不会立即删除,可能被 MVCC 或未提交事务引用。
- 当所有依赖该 Undo Log 的事务结束后,由后台线程(Purge Thread)清理无用的 Undo Log。
4. 示例:UPDATE 操作的回滚
假设事务 A 执行以下操作:
-- 原始数据:id=1, name='Bob', age=20
UPDATE users SET name = 'Alice' WHERE id = 1;
UPDATE users SET age = 25 WHERE id = 1;
COMMIT;
若事务 A 在提交前回滚:
- 逆向处理第二条
UPDATE
:将age=25
恢复为age=20
。 - 逆向处理第一条
UPDATE
:将name='Alice'
恢复为name='Bob'
。
5. Undo Log 的存储与管理
- 存储位置:Undo Log 存储在 回滚段(Rollback Segments) 中,每个回滚段包含多个 Undo Slot。
- 持久化:Undo Log 写入磁盘的
undo tablespace
(默认文件为undo_001
、undo_002
),但写入时仅追加到内存的 Undo Buffer,异步刷盘。 - 崩溃恢复:数据库重启时,通过 Redo Log 恢复 Undo Log,再根据 Undo Log 回滚未提交的事务。
6. Undo Log 与 MVCC
除了回滚,Undo Log 还支持 MVCC:
- 当一个事务执行
SELECT
查询时,会基于当前活跃事务 ID 列表,通过 Undo Log 版本链找到可见的旧版本数据(快照读),避免阻塞写操作。
7. 关键参数优化
innodb_undo_tablespaces
:设置 Undo Log 表空间数量(默认 2)。innodb_max_undo_log_size
:单个 Undo 表空间的最大大小(默认 1GB)。innodb_undo_log_truncate
:启用自动清理 Undo Log 空间(避免膨胀)。
总结
- Undo Log 是事务原子性的基石:通过记录旧值,确保事务可以回滚到修改前的状态。
- 回滚流程:逆向应用 Undo Log,按操作类型恢复数据。
- 与 MVCC 协同:支持非锁定读,提升并发性能。
- 设计权衡:Undo Log 需要平衡空间占用、性能开销和一致性要求。