0%

事务的实现

MySQL 事务的实现机制:redo log 与 undo log 详解

MySQL 事务的 ACID 特性(原子性、一致性、隔离性、持久性)依赖于底层的日志机制和锁机制。其中,redo log(重做日志)undo log(回滚日志) 是保障事务持久性和原子性的核心组件,配合 “日志先行(Write-Ahead Logging, WAL)” 策略,实现了高效且可靠的事务处理。

事务实现的核心思想:日志先行(WAL)

MySQL 执行事务时,采用 “先写日志,再写数据” 的策略(WAL),即:

  • 事务修改数据前,先将修改操作记录到日志中;
  • 确保日志写入磁盘后,再异步将数据更新到磁盘中的数据文件(如 .ibd)。

这一策略的优势在于:

  • 日志文件是顺序写入的,而数据文件的修改可能是随机的(效率更高);
  • 即使系统崩溃,未写入数据文件的修改可通过日志恢复,保证事务持久性。

redo log:保障事务的持久性

redo log 的作用

redo log 记录了事务对数据页的修改操作(如 “将 id=1 的行的 name 字段从 ‘A’ 改为 ‘B’”),用于在系统崩溃后恢复未写入数据文件的已提交事务,确保已提交的事务不会丢失(持久性)。

redo log 的写入流程

redo log 的写入涉及三个关键区域:

  1. redo log buffer(内存缓冲区)
    事务执行过程中,修改操作会先记录到内存中的 redo log buffer(速度快,无需磁盘 IO)。
  2. os buffer(操作系统缓冲区)
    当事务提交或满足一定条件时,redo log buffer 中的日志会被复制到操作系统的缓冲区(os buffer)。
  3. redo log file(磁盘日志文件)
    最终通过 fsync() 系统调用将 os buffer 中的日志写入磁盘上的 redo log 文件(默认名为 ib_logfile0ib_logfile1)。

刷盘策略:innodb_flush_log_at_trx_commit 参数

该参数控制事务提交时 redo log 的刷盘时机,直接影响安全性和性能:

参数值 刷盘策略 安全性(数据可靠性) 性能 适用场景
0 延迟写:事务提交时不刷盘,每秒将 redo log buffer 写入 os buffer 并调用 fsync() 低(崩溃可能丢失 1 秒数据) 最好 对数据安全性要求低的场景(如日志收集)
1 实时写 + 实时刷:事务提交时,立即将 redo log buffer 写入 os buffer 并调用 fsync() 高(无数据丢失) 最差 核心业务(如金融交易)
2 实时写 + 延迟刷:事务提交时写入 os buffer,但每秒调用 fsync() 刷盘一次。 中(崩溃可能丢失 os buffer 中的数据) 较好 大多数非核心业务
  • 默认值为 1,确保事务持久性(ACID 中的 D),这是 MySQL 对事务安全的默认保证。

redo log 的其他特性

  • 循环写入:redo log 文件大小固定(由 innodb_log_file_sizeinnodb_log_files_in_group 控制),写满后覆盖旧日志(已写入数据文件的日志可被覆盖)。
  • LSN 关联:每个 redo log 记录包含 LSN(Log Sequence Number,日志序列号),用于标记日志顺序和数据页的一致性(数据页的 LSN 需与日志 LSN 匹配)。

undo log:保障事务的原子性

undo log 的作用

undo log 记录了事务修改数据前的原始状态(如 “id=1 的行的 name 字段原本是 ‘A’”),用于:

  • 事务回滚:当事务执行失败或调用 ROLLBACK 时,通过 undo log 恢复数据到修改前的状态(保证原子性)。
  • MVCC(多版本并发控制):为读取操作提供历史版本数据,实现 “读不加锁”,提升并发性能。

undo log 的写入与存储

  • 写入时机:事务执行修改操作时,先记录 undo log(与 redo log 类似,先写入 buffer,再刷盘)。
  • 存储位置:默认存储在系统表空间(ibdata1),MySQL 5.6+ 支持独立 undo 表空间(通过 innodb_undo_tablespaces 配置),便于管理和回收空间。

undo log 的生命周期

  • 活跃期:事务未提交时,undo log 处于 “活跃” 状态,不能被删除(需支持回滚或 MVCC 读取)。
  • 过期回收:事务提交后,undo log 变为 “非活跃” 状态,当不再被 MVCC 读取(如没有事务需要访问该历史版本)时,由后台线程(purge 线程)回收。

redo log 与 undo log 的协同工作

事务的完整执行流程中,redo log 和 undo log 配合保障 ACID 特性:

  1. 事务开始:MySQL 为事务分配事务 ID,记录初始 LSN。
  2. 执行修改:
    • 读取数据页到内存(buffer pool)。
    • 生成 undo log(记录原始数据),写入 undo log buffer。
    • 修改内存中的数据页,生成 redo log(记录修改操作),写入 redo log buffer。
  3. 事务提交:
    • 根据 innodb_flush_log_at_trx_commit 策略,将 redo log 刷入磁盘。
    • 标记事务为 “已提交”,释放 undo log 的活跃状态。
  4. 崩溃恢复:
    • 重启时,通过 redo log 恢复所有已提交但未写入数据文件的修改。
    • 通过 undo log 回滚所有未提交的事务(保证原子性)

欢迎关注我的其它发布渠道