找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

710

积分

0

好友

100

主题
发表于 4 天前 | 查看: 14| 回复: 0

MySQL InnoDB 引擎有两大核心日志,共同支撑起数据库的事务与持久化能力:

  • redo log(重做日志)
  • undo log(回滚日志)

一个的核心目标是崩溃恢复,另一个则保证了事务回滚与MVCC(多版本并发控制)。它们的作用完全不同,但共同构成了InnoDB可靠性的基石。

本文将深入解析两者的用途、原理、工作流程与核心差异。

一、undo log 的作用:实现“逻辑回滚”与 MVCC

undo log 主要承担两个关键职责:

1. 事务回滚(撤销变更)

当执行一条更新语句时,例如:

UPDATE user SET age=20 WHERE id=1;

InnoDB 会按顺序执行以下操作:

  1. 将修改前的数据(旧值)记录到 undo log 中。
  2. 在内存的数据页(Buffer Pool)中写入新数据。

如果事务最终决定回滚(ROLLBACK),InnoDB 便可以依据 undo log 中保存的旧值,将数据恢复到修改前的状态,从而保证了事务的原子性(Atomicity)。因此,undo log 常被称为“撤销日志”。

2. 支持 MVCC(多版本并发控制)

在 InnoDB 中,每次对数据进行更新时,旧版本的数据并不会被立即删除,而是通过一个名为 roll_pointer 的指针,将多个旧版本串联成一条版本链,存储于 undo log 中。

当前版本 (v3) → 上一版本 (v2) → 更早版本 (v1) ...

当执行一个普通的 SELECT 查询(快照读)时,该操作无需加锁。它会根据当前事务的 Read View(一致性视图),沿着这条 undo log 版本链,找到自己可见的那个数据版本进行读取。可以说,没有 undo log,MVCC 机制就无法实现。

二、redo log 的作用:确保“崩溃恢复”与事务持久性

redo log 的核心使命非常明确:
确保数据库发生崩溃后,所有已提交的事务修改都不会丢失,从而保证事务的持久性(Durability)。

其背后的核心思想是 WAL(Write-Ahead Logging,预写式日志) 策略:先写日志,再写数据页。

工作流程如下:

事务提交
    ↓
redo log 优先写入磁盘(顺序IO,速度快)
    ↓
后台进程异步将内存中修改过的数据页刷回磁盘(随机IO)

如果在这个过程完成前系统突然宕机:

  • 内存(Buffer Pool)中已修改的数据页可能未来得及写入磁盘。
  • 但记录着这些修改的 redo log 已经持久化到了磁盘上。
  • 当数据库重启进行崩溃恢复时,会重放(redo) redo log 中的记录,从而将已提交但未落盘的数据重新构造出来,确保数据不丢失。

这便是 redo log 实现持久性(Durability) 的核心机制。对数据库/中间件的可靠性和性能而言,这套机制至关重要。

三、undo log 与 redo log 的核心区别对比

对比项目 undo log redo log
核心作用 事务回滚、实现 MVCC 崩溃恢复
日志类型 逻辑日志(记录如何撤销,即旧值) 物理日志(记录修改了哪个数据页及具体变化)
记录内容 修改前的数据状态(旧值) 修改后的物理页变化(新值)
写入时机 执行 UPDATE/DELETE 时立即记录 数据页在内存中被修改后,立即记录到 redo log buffer
主要保证 原子性 (A),一致性 (C) 的一部分 持久性 (D)
与MVCC关系 核心基础 无直接关系
数据恢复方向 向前恢复“旧数据”(回滚) 向前重做“新数据”(重放)

一句话总结:

  • undo log 记录“过去”,保存旧值,用于回滚到历史状态。
  • redo log 记录“未来”,保存新值,用于重做到目标状态。

四、为什么需要两套日志?(高频面试点)

既然两者都能恢复数据,为何缺一不可?

  1. redo log 无法用于回滚:redo log 记录的是“修改后的新值”和物理位置。而回滚需要的是“修改前的旧值”,redo log 不具备这个信息。
  2. undo log 不能用于崩溃恢复:undo log 本身也存储在表空间(如系统表空间)中,但它没有采用 WAL 机制。在崩溃发生时,undo log 自身的修改可能还未落盘,因此无法依赖它进行数据恢复。
  3. 目标截然不同:两者服务于事务 ACID 特性的不同方面,功能上无法相互替代。

五、核心工作顺序与设计逻辑

一个 UPDATE 语句在 InnoDB 内部的典型执行顺序是:

1. 写 undo log(记录旧值,为回滚做准备)
2. 修改 Buffer Pool 中的内存数据页
3. 写 redo log(记录“数据页已被修改”这个物理变化)
4. 事务提交(触发 redo log 落盘)
5. 后台线程异步刷脏页(将内存数据页写回磁盘)

关键顺序是:undo log → 内存修改 → redo log。

为什么必须先写 undo log?
这是为了保证事务的原子性(A)。必须在修改实际数据之前,就将回滚所需的旧值妥善保存。如果顺序反过来,先写了 redo log(记录了新数据),但事务随后失败需要回滚,此时将没有 undo log 来恢复旧值,导致数据损坏,原子性被破坏。

六、业务视角下的真实意义

  • undo log 让你可以

    • 在业务逻辑出错时,安全地回滚整个事务。
    • 在高并发场景下,其他事务可以无阻塞地读取数据的历史快照(MVCC),极大提升系统并发能力。
  • redo log 让你可以

    • 即使服务器意外断电重启,已提交的业务数据也绝对不会丢失
    • 通过将随机写磁盘转化为顺序写数据库/中间件的日志,大幅提升写入性能,支持高并发写入场景。

七、总结

  • undo log 保存数据修改前的版本,是一种逻辑日志。它主要用于事务回滚和支持 MVCC,是保证事务原子性(A) 的关键。
  • redo log 记录数据页修改后的物理变化,是一种物理日志。它采用 WAL 策略,专用于崩溃恢复,是保证事务持久性(D) 的关键。

二者相辅相成,共同构成了 MySQL InnoDB 存储引擎实现事务 ACID 特性的核心支柱。




上一篇:RTOS对比与选型指南:详解FreeRTOS、RT-Thread等6款主流嵌入式系统特点
下一篇:Swagger未授权访问实战复现:从接口泄露到逻辑漏洞挖掘
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-13 18:47 , Processed in 0.079683 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表