【MySQL | 第一篇】 深入理解三大日志(undo Redo Bin)

目录

[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事务原子性、一致性的核心保障。

二、核心作用

  1. 事务回滚

事务执行失败/手动ROLLBACK时,通过Undo Log还原数据到执行前状态,保证事务要么全部成功,要么全部失败。

  1. MVCC

实现快照读(一致性非锁定读),读取历史数据版本,避免读写阻塞,提升并发性能。

  1. 崩溃恢复

数据库崩溃重启时,利用Undo Log回滚未提交事务,保证数据一致性。

三、存储结构与类型

  1. 存储位置
  • 不单独存文件,存储在InnoDB的共享 表空间 (ibdata1)独立undo表空间

  • 分为回滚段(Rollback Segment),默认128个回滚段,每个回滚段管理多个Undo Log。

  1. 两种类型

(1)INSERT Undo Log

  • 仅记录INSERT操作的反向信息(删除插入的行)。

  • 事务提交后立即删除(无MVCC复用价值,因为是新数据,没有历史undo log链条)。

(2)UPDATE Undo Log

  • 记录UPDATE/DELETE操作的旧数据版本。

  • 事务提交后不立即删除 ,保留供MVCC读取历史版本,由purge线程异步清理。

四、工作原理

  1. 事务执行流程

  2. 事务开始,InnoDB分配Undo Log空间。

  3. 执行DML(INSERT/UPDATE/DELETE):

    1. 先写Undo Log(记录旧数据)。

    2. 再修改Buffer Pool中的数据页。

  4. 事务提交:

    1. INSERT Undo Log直接删除。

    2. UPDATE Undo Log标记为可清理,等待purge线程回收。

  5. 事务回滚:

    1. 读取Undo Log,执行反向操作还原数据。
  6. MVCC实现原理

  • 每行数据隐含trx_id(事务ID)roll_pointer(回滚指针)

  • roll_pointer指向Undo Log中的历史版本链

  • 快照读时,根据事务ID读取对应版本,无需加锁。

五、Purge线程(清理机制)

  1. 作用

异步清理已提交、无活跃事务引用的UPDATE Undo Log,释放空间。

  1. 触发条件
  • 事务提交后,Undo Log标记为可清理。

  • 系统空闲时,purge线程批量清理。

  1. 影响

清理不及时会导致Undo Log膨胀,占用磁盘空间,影响性能。

Redo Log日志

redo log(重做日志) 是 InnoDB 存储引擎独有的物理日志 ,核心作用:保证事务持久性、崩溃恢复、提升写入性能 ,是 InnoDB 实现 ACID 中 D(持久性) 的关键。

一、作用

  1. 崩溃恢复

MySQL 宕机重启后,通过 redo log 恢复未刷盘的脏页数据,避免数据丢失。

  1. 提升写入性能

事务提交时,先写 redo log(顺序写),再异步刷脏页到磁盘(随机写),顺序写远快于随机写。

  1. 保证持久性

只要 redo log 落盘,事务就"持久化成功",即使内存数据丢失也能恢复。

二、内容

数据页的物理修改(如"在第100号数据页的第20个偏移量写入值10")。

每条redo记录由"表空间号+数据页号+偏移量+修改数据长度+具体修改的数据"组成

三、两阶段写入(WAL 机制)

声明:两阶段写入(WAL)两阶段提交(prepare + commit) 不一样

WAL(Write-Ahead Logging,预写日志):先写日志,再写数据。(说的是磁盘阶段,先落盘日志,再刷盘数据页)

  1. 事务修改数据 → 内存中修改脏页(未刷盘)。

  2. 生成 redo log → 写入 redo log buffer。

  3. 事务提交 → redo log buffer 刷入磁盘(commit 必须落盘)。

  4. 后台线程异步将脏页刷入磁盘。

这里所说的脏页是在缓冲池中的数据页
本质:先改内存中的数据,在写内存中的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. =1(默认,性能低,最安全)

每次事务提交,redo log 必刷磁盘(fsync),不丢数据

  1. =2(性能和安全居中)

提交时写入操作系统文件缓存每秒刷一次磁盘;MySQL挂了不丢,操作系统宕机可能丢 1 秒数据。

  1. =0(高性能,不安全)

仅后台线程每秒刷盘;MySQL/OS 宕机都可能丢数据。

Redo Log与Bin Log的区别

|------|-------------|------------------|
| 特性 | redo log | binlog |
| 引擎 | InnoDB 独有 | MySQL 服务层,所有引擎通用 |
| 日志类型 | 物理日志(数据页修改) | 逻辑日志(SQL/行变化) |
| 作用 | 崩溃恢复 | 主从复制、数据恢复 |
| 写入方式 | 循环写(固定大小) | 追加写(无限增长) |
| 写入时机 | 事务执行中持续写 | 事务提交时一次性写 |

关键!!!

  1. 写入内存时机

redo log:执行时写 buffer

bin log:执行时写 cache

两者都是边执行边写内存

  1. 写入磁盘时机(最大区别)

redo log: 随时刷 (后台 / 满了 / 提交)

bin log:必须 提交才刷

  1. 事务未提交时

redo log:可能已经刷盘

bin log:绝对不会刷盘

  1. 崩溃时

redo log:可恢复未提交事务(崩溃恢复)

bin log:未提交事务不会存在(因为没刷盘)

Bin Log日志

bin log 是 MySQL 记录所有数据库结构变更、数据修改 的二进制日志,不记录查询类操作

一、作用

  1. 数据恢复:通过 bin log 回滚误操作、恢复到指定时间点

  2. 主从复制:主库将 bin log 发给从库,从库重放实现数据同步

  3. 审计:追溯数据库的所有修改操作

二、记录内容

  • 只记录写操作: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

五、主从复制

主库

  1. 事务提交 → 写入 bin log

  2. dump 线程读取 bin log

  3. 发送给从库

从库

  1. IO 线程 接收 → 写入 relay log

  2. SQL 线程读取 relay log → 重放 SQL

  3. 从库数据与主库一致

六、日志文件组成

  1. 二进制日志文件mysql-bin.000001mysql-bin.000002... 写满自动滚动

  2. 索引文件mysql-bin.index,记录所有 bin log 文件名列表

三大日志全流程

伪代码:

复制代码
BEGIN;
    UPDATE ...;
    INSERT ...;
COMMIT;

一、BEGIN(事务开始)

  • InnoDB 分配 Undo Log 空间

  • 事务开始,状态:活跃、未提交

  • 此时:

    • 无 prepare

    • 无 commit

    • 无 Bin Log

    • 只有 Undo Log 准备好

二、执行 UPDATE ...

顺序:Undo → 改内存 → Redo

  1. 写 Undo Log(UPDATE 类型)

    1. 记录修改前的旧数据

    2. 用于回滚 + MVCC

  2. 修改 Buffer Pool 数据页(在内存中,是数据本身的缓存区,和日志无关)

  3. 写 Redo Log Buffer(普通 redo,不是 prepare)

    1. 记录物理修改

    2. 还没落盘,只是内存

三、执行 INSERT ...

同样顺序:Undo → 内存 → Redo

  1. 写 Undo Log(INSERT 类型)

  2. 修改 Buffer Pool

  3. 写 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类事务:
  1. Redo Log 标记为 commit:事务已完成两阶段提交

  2. Redo Log 标记为 prepare:事务卡在提交过程中(只完成 prepare,没到 commit)

  3. 无 prepare/commit 标记:事务只执行了 DML 没触发 commit,属于 "未提交事务"

++对于上面3类事务,对应下面的三种情况++

  1. Redo Log 标记为 commit

    1. 判断:事务已完全提交(Bin Log已写成功,否则到不了commit 阶段)

    2. 处理:执行Redo Log 重做(把修改同步到磁盘)

  2. Redo Log 标记为 prepare

    1. 校验 Bin Log:检查 Bin Log 中是否有该事务的完整记录(通过事务 ID 匹配)

      1. Bin Log 有该事务

        • 说明 "写 Bin Log" 步骤已完成,只是没来得及写 Redo commit

        • 处理:InnoDB 会补全 Redo commit 标记,然后重做 Redo Log,最终提交事务

      2. Bin Log 无该事务

        • 说明 "写 Bin Log" 步骤没完成就崩溃了

        • 处理:用 Undo Log 回滚该事务,恢复到修改前的状态

  3. 无 prepare/commit 标记(只执行了 DML 没触发 commit)

    1. 判断:事务从未进入提交流程,属于未提交事务

    2. 处理:用 Undo Log 直接回滚,恢复数据到事务执行前的状态

补充:

  1. "Redo prepare → 写 Bin Log → Redo commit" 的顺序是硬约束

    1. 只有 Bin Log 落盘成功,才会执行 Redo commit

    2. 所以 "Redo commit" 一定意味着 Bin Log 已写成功,无需再校验

  2. Bin Log 是 "最终证据"

    1. MySQL 保证:Bin Log 写成功 = 事务可以安全提交

    2. Bin Log 没写成功 = 事务必须回滚(否则主从复制会丢数据)

  3. Undo Log 只用于回滚

    1. 只有 "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

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,你们的支持就是我坚持下去的动力!

相关推荐
oradh1 小时前
Oracle OJVM组件总结
数据库·oracle·ojvm·ojvm补丁
爱写Bug的小孙2 小时前
多智能体概述
服务器·数据库·ai·oracle·agent·多智能体·agentscop
路由侠内网穿透2 小时前
本地部署开源零信任网络平台 NetBird 并实现外部访问
运维·服务器·数据库·开源
2301_804215412 小时前
使用Python进行量化交易入门
jvm·数据库·python
霑潇雨2 小时前
题解 | 深入分析各款产品年总销售额与竞品的年度对比
大数据·开发语言·数据库
scofield_gyb2 小时前
Redis 6.2.7安装配置
前端·数据库·redis
qiumingxun2 小时前
Redis——使用 python 操作 redis 之从 hmse 迁移到 hset
数据库·redis·python
2401_873544922 小时前
使用XGBoost赢得Kaggle比赛
jvm·数据库·python
ruxingli2 小时前
MySQL优化
数据库·mysql