目录
[Undo Log日志](#Undo Log日志)
[Redo Log日志](#Redo Log日志)
[Redo Log与Bin Log的区别](#Redo Log与Bin Log的区别)
[Bin Log日志](#Bin Log日志)
Undo Log日志
一、核心定义
Undo Log 是MySQL InnoDB存储引擎特有的事务回滚日志 ,核心作用是记录事务执行前的数据版本,用于事务回滚、MVCC实现,是InnoDB事务原子性、一致性的核心保障。
二、核心作用
- 事务回滚
事务执行失败/手动ROLLBACK时,通过Undo Log还原数据到执行前状态,保证事务要么全部成功,要么全部失败。
- MVCC
实现快照读(一致性非锁定读),读取历史数据版本,避免读写阻塞,提升并发性能。
- 崩溃恢复
数据库崩溃重启时,利用Undo Log回滚未提交事务,保证数据一致性。
三、存储结构与类型
- 存储位置
-
不单独存文件,存储在InnoDB的共享 表空间 (ibdata1) 或独立undo表空间。
-
分为回滚段(Rollback Segment),默认128个回滚段,每个回滚段管理多个Undo Log。
- 两种类型
(1)INSERT Undo Log
-
仅记录INSERT操作的反向信息(删除插入的行)。
-
事务提交后立即删除(无MVCC复用价值,因为是新数据,没有历史undo log链条)。
(2)UPDATE Undo Log
-
记录UPDATE/DELETE操作的旧数据版本。
-
事务提交后不立即删除 ,保留供MVCC读取历史版本,由purge线程异步清理。
四、工作原理
-
事务执行流程
-
事务开始,InnoDB分配Undo Log空间。
-
执行DML(INSERT/UPDATE/DELETE):
-
先写Undo Log(记录旧数据)。
-
再修改Buffer Pool中的数据页。
-
-
事务提交:
-
INSERT Undo Log直接删除。
-
UPDATE Undo Log标记为可清理,等待purge线程回收。
-
-
事务回滚:
- 读取Undo Log,执行反向操作还原数据。
-
MVCC实现原理
-
每行数据隐含trx_id(事务ID) 、roll_pointer(回滚指针)。
-
roll_pointer指向Undo Log中的历史版本链。
-
快照读时,根据事务ID读取对应版本,无需加锁。
五、Purge线程(清理机制)
- 作用
异步清理已提交、无活跃事务引用的UPDATE Undo Log,释放空间。
- 触发条件
-
事务提交后,Undo Log标记为可清理。
-
系统空闲时,purge线程批量清理。
- 影响
清理不及时会导致Undo Log膨胀,占用磁盘空间,影响性能。
Redo Log日志
redo log(重做日志) 是 InnoDB 存储引擎独有的物理日志 ,核心作用:保证事务持久性、崩溃恢复、提升写入性能 ,是 InnoDB 实现 ACID 中 D(持久性) 的关键。
一、作用
- 崩溃恢复
MySQL 宕机重启后,通过 redo log 恢复未刷盘的脏页数据,避免数据丢失。
- 提升写入性能
事务提交时,先写 redo log(顺序写),再异步刷脏页到磁盘(随机写),顺序写远快于随机写。
- 保证持久性
只要 redo log 落盘,事务就"持久化成功",即使内存数据丢失也能恢复。
二、内容
数据页的物理修改(如"在第100号数据页的第20个偏移量写入值10")。
每条redo记录由"表空间号+数据页号+偏移量+修改数据长度+具体修改的数据"组成
三、两阶段写入(WAL 机制)
声明:两阶段写入(WAL)两阶段提交(prepare + commit) 不一样
WAL(Write-Ahead Logging,预写日志):先写日志,再写数据。(说的是磁盘阶段,先落盘日志,再刷盘数据页)
-
事务修改数据 → 内存中修改脏页(未刷盘)。
-
生成 redo log → 写入 redo log buffer。
-
事务提交 → redo log buffer 刷入磁盘(commit 必须落盘)。
-
后台线程异步将脏页刷入磁盘。
这里所说的脏页是在缓冲池中的数据页
本质:先改内存中的数据,在写内存中的redo log,
之后先刷盘log,最后再异步刷盘数据
三、组成:buffer + 磁盘文件
1. redo log buffer(内存)
-
临时存放 redo log。
-
刷盘时机:
-
事务提交(默认
innodb_flush_log_at_trx_commit=1,必刷)。 -
每秒后台线程刷一次。
-
buffer 满 1/2 时自动刷。
-
2. redo log file(磁盘)
-
固定大小、循环使用的日志文件。
-
两个关键指针:
-
write pos: 是当前记录的位置,一边写一边后移
-
checkpoint:是当前要擦除的位置,也是往后推移
-
-
可用空间 =
write pos ~ checkpoint;写满则阻塞写入,等待 checkpoint 推进。

四、刷盘策略
补充的是三中的:redo log buffer(内存)
决定 redo log 落盘强度,直接影响性能 vs 数据安全:
- =1(默认,性能低,最安全)
每次事务提交,redo log 必刷磁盘(fsync),不丢数据。
- =2(性能和安全居中)
提交时写入操作系统文件缓存 ,每秒刷一次磁盘;MySQL挂了不丢,操作系统宕机可能丢 1 秒数据。
- =0(高性能,不安全)
仅后台线程每秒刷盘;MySQL/OS 宕机都可能丢数据。
Redo Log与Bin Log的区别
|------|-------------|------------------|
| 特性 | redo log | binlog |
| 引擎 | InnoDB 独有 | MySQL 服务层,所有引擎通用 |
| 日志类型 | 物理日志(数据页修改) | 逻辑日志(SQL/行变化) |
| 作用 | 崩溃恢复 | 主从复制、数据恢复 |
| 写入方式 | 循环写(固定大小) | 追加写(无限增长) |
| 写入时机 | 事务执行中持续写 | 事务提交时一次性写 |
关键!!!
- 写入内存时机
redo log:执行时写 buffer
bin log:执行时写 cache
→ 两者都是边执行边写内存
- 写入磁盘时机(最大区别)
redo log: 随时刷 (后台 / 满了 / 提交)
bin log:必须 提交才刷
- 事务未提交时
redo log:可能已经刷盘
bin log:绝对不会刷盘
- 崩溃时
redo log:可恢复未提交事务(崩溃恢复)
bin log:未提交事务不会存在(因为没刷盘)
Bin Log日志
bin log 是 MySQL 记录所有数据库结构变更、数据修改 的二进制日志,不记录查询类操作
一、作用
-
数据恢复:通过 bin log 回滚误操作、恢复到指定时间点
-
主从复制:主库将 bin log 发给从库,从库重放实现数据同步
-
审计:追溯数据库的所有修改操作
二、记录内容
-
只记录写操作:INSERT、UPDATE、DELETE、CREATE、ALTER、DROP、TRUNCATE 等
-
不记录读操作:SELECT、SHOW、DESC 等
-
记录事务提交:InnoDB 事务提交后才写入 bin log(保证一致性)
三、三种记录格式
1. STATEMENT(语句级,默认早期)
-
记录执行的 SQL 语句
-
优点:日志量小、性能好
-
缺点:不确定函数(NOW()、UUID()、RAND())、存储过程会导致主从数据不一致
2. ROW(行级,推荐)
-
记录每行数据的变更(修改前/后的值)
-
优点:主从绝对一致、恢复精准
-
缺点:日志量大、批量操作(如 UPDATE 全表)日志暴增
3. MIXED(混合)
-
普通 SQL 用 STATEMENT,不确定函数用 ROW
-
兼顾性能与一致性,折中方案
四、刷盘策略
关键参数 sync_binlog
=1 :每次提交事务都会执行fsync
=0 :每次提交事务都只write,由系统自行判断什么时候执行fsync
=N :每次提交事务都write,但累积N个事务后才fsync

五、主从复制
主库
-
事务提交 → 写入 bin log
-
dump 线程读取 bin log
-
发送给从库
从库
-
IO 线程 接收 → 写入 relay log
-
SQL 线程读取 relay log → 重放 SQL
-
从库数据与主库一致
六、日志文件组成
-
二进制日志文件 :
mysql-bin.000001、mysql-bin.000002... 写满自动滚动 -
索引文件 :
mysql-bin.index,记录所有 bin log 文件名列表
三大日志全流程
伪代码:
BEGIN;
UPDATE ...;
INSERT ...;
COMMIT;
一、BEGIN(事务开始)
-
InnoDB 分配 Undo Log 空间
-
事务开始,状态:活跃、未提交
-
此时:
-
无 prepare
-
无 commit
-
无 Bin Log
-
只有 Undo Log 准备好
-
二、执行 UPDATE ...
顺序:Undo → 改内存 → Redo
-
写 Undo Log(UPDATE 类型)
-
记录修改前的旧数据
-
用于回滚 + MVCC
-
-
修改 Buffer Pool 数据页(在内存中,是数据本身的缓存区,和日志无关)
-
写 Redo Log Buffer(普通 redo,不是 prepare)
-
记录物理修改
-
还没落盘,只是内存
-
三、执行 INSERT ...
同样顺序:Undo → 内存 → Redo
-
写 Undo Log(INSERT 类型)
-
修改 Buffer Pool
-
写 Redo Log Buffer
此时:
-
事务仍未提交
-
无 prepare
-
无 commit
-
无 Bin Log
-
只有 Undo Log、Redo Log Buffer、内存数据
四、执行 COMMIT(最关键:两阶段提交)
只有执行 COMMIT,才会进入 prepare → binlog → commit
第1步:Redo prepare(准备提交)
-
Redo Log 标记为 prepare
-
事务进入提交中状态
-
此时:还不算提交成功
第2步:写 Bin Log(落盘)
-
把整个事务的逻辑操作写入 Bin Log
-
Bin Log 必须落盘成功
-
此时:仍不算提交成功
第3步:Redo commit(真正提交)
-
Redo Log 标记为 commit
-
这一刻,事务才算真正提交成功
-
不可回滚
五、提交完成后
-
INSERT Undo Log:立即删除
-
UPDATE Undo Log:保留,等待 purge 线程清理
-
Redo Log:后台刷盘
-
Bin Log:追加写入,永久保留
-
数据页:后台刷盘
六、崩溃时怎么判断
- 数据库在
COMMIT过程中崩溃,重启后 InnoDB 会执行崩溃恢复**,先扫描 Redo Log** ,找出所有 "未收尾" 的事务**,**筛选出3类事务:
-
Redo Log 标记为 commit:事务已完成两阶段提交
-
Redo Log 标记为 prepare:事务卡在提交过程中(只完成 prepare,没到 commit)
-
无 prepare/commit 标记:事务只执行了 DML 没触发 commit,属于 "未提交事务"
++对于上面3类事务,对应下面的三种情况++
-
Redo Log 标记为 commit
-
判断:事务已完全提交(Bin Log已写成功,否则到不了commit 阶段)
-
处理:执行Redo Log 重做(把修改同步到磁盘)
-
-
Redo Log 标记为 prepare
-
校验 Bin Log:检查 Bin Log 中是否有该事务的完整记录(通过事务 ID 匹配)
-
✅ Bin Log 有该事务:
-
说明 "写 Bin Log" 步骤已完成,只是没来得及写 Redo commit
-
处理:InnoDB 会补全 Redo commit 标记,然后重做 Redo Log,最终提交事务
-
-
❌ Bin Log 无该事务:
-
说明 "写 Bin Log" 步骤没完成就崩溃了
-
处理:用 Undo Log 回滚该事务,恢复到修改前的状态
-
-
-
-
无 prepare/commit 标记(只执行了 DML 没触发 commit)
-
判断:事务从未进入提交流程,属于未提交事务
-
处理:用 Undo Log 直接回滚,恢复数据到事务执行前的状态
-
补充:
"Redo prepare → 写 Bin Log → Redo commit" 的顺序是硬约束:
只有 Bin Log 落盘成功,才会执行 Redo commit
所以 "Redo commit" 一定意味着 Bin Log 已写成功,无需再校验
Bin Log 是 "最终证据":
MySQL 保证:Bin Log 写成功 = 事务可以安全提交
Bin Log 没写成功 = 事务必须回滚(否则主从复制会丢数据)
Undo Log 只用于回滚:
- 只有 "Bin Log 无记录" 或 "未进入提交流程" 的事务,才会触发 Undo Log 回滚
七、总结
BEGIN → 写 Undo → 改内存 → 写 Redo(普通)
COMMIT → Redo prepare → 写 Bin Log → Redo commit(真正提交)
崩溃:prepare 看 Bin Log,有就提交,无就回滚
上述内容也同步在我的飞书,欢迎访问
https://my.feishu.cn/wiki/QLauws6lWif1pnkhB8IcAvkhncc?from=from_copylink
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,你们的支持就是我坚持下去的动力!