Skip to content

事务回滚的原理

约 856 字大约 3 分钟

MySQL美团

2025-04-08

⭐ 题目日期:

美团 - 2025/4/4

📝 题解:

事务回滚的原理基于数据库的UNDO日志机制,通过记录数据修改前的状态,在事务失败或显式回滚时逆向恢复数据,确保事务的原子性和数据一致性。以下是其核心实现步骤:


1. UNDO日志的作用

  • 记录旧值
    事务执行数据修改(增、删、改)前,将数据修改前的状态(旧值)写入UNDO日志。
  • 支持回滚
    通过UNDO日志逆向恢复数据到事务开始前的状态。
  • 实现MVCC
    在并发控制中,其他事务可能依赖UNDO日志访问旧版本数据(如读已提交、可重复读隔离级别)。

2. 回滚的核心流程

步骤1:事务开始

  • 分配唯一事务ID,开启UNDO日志记录。

步骤2:记录UNDO日志

  • 插入操作:记录新插入行的主键,回滚时删除该行。
  • 删除操作:记录被删除行的完整内容,回滚时重新插入。
  • 更新操作:记录被修改字段的旧值,回滚时还原。

步骤3:执行回滚

  • 按操作逆序(后进先出)遍历UNDO日志,逐条恢复数据。
    示例:事务执行顺序为 UPDATE → DELETE → INSERT
    回滚顺序为:撤销INSERT → 恢复DELETE → 还原UPDATE

步骤4:清理资源

  • 释放事务持有的锁(行锁、表锁等)。
  • 标记UNDO日志空间为可复用。

3. UNDO日志的存储与管理

  • 存储位置
    通常存储在**回滚段(Rollback Segment)**中,每个事务对应一个UNDO日志链表。
  • 空间复用
    已提交或回滚的事务的UNDO日志可被覆盖,未提交的事务日志需保留。
  • 清理机制
    数据库后台线程定期清理过期UNDO日志(如MySQL的Purge线程)。

4. 与并发控制的交互

  • MVCC(多版本并发控制)
    • 读操作通过UNDO日志访问旧版本数据,避免读写冲突。
    • 回滚时,只需标记事务版本无效,不影响其他事务的读一致性。
  • 锁机制
    • 回滚释放锁后,其他被阻塞的事务可继续执行。

5. 不同操作的回滚实现

操作类型UNDO日志内容回滚动作
INSERT新插入行的主键根据主键删除该行
DELETE被删除行的完整数据重新插入该行
UPDATE被修改字段的旧值将字段还原为旧值

6. 性能优化与挑战

  • 日志写入优化
    UNDO日志顺序写入磁盘,减少随机I/O开销。
  • 大事务处理
    长时间未提交的事务会导致UNDO日志堆积,可能引发存储压力,需避免长事务。
  • 崩溃恢复
    数据库重启时,未提交的事务自动通过UNDO日志回滚。

7. 示例:事务回滚过程

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- UNDO记录balance旧值
UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- UNDO记录balance旧值
ROLLBACK;  -- 按逆序恢复id=2和id=1的balance值

总结

事务回滚通过UNDO日志逆向恢复数据,确保事务的原子性,同时结合锁和MVCC机制保障并发一致性。其核心是记录旧状态、逆序恢复、资源清理,是数据库实现ACID特性的基石。