Java 王者修炼手册【Mysql 篇 - 日志】:吃透 MySQL redo log + undo log + binlog 底层机制

大家好,我是程序员强子。
昨天学习了 Mysql 四大金刚之一的 索引 ,今天则专注把另一个金刚 日志 相关给弄明白~
redo log /undo log / binlog 核心作用,特点,工作流程,案例
两阶段提交 /double write /write-aheard-logging (WAL) 到底是什么?有什么作用?使用它们目的是什么?
干货很多,来不及解释,赶紧上车~
redo log
是 ACID 中的 D ,持久性
文件格式 & 内容
格式
ib_logfile + 数字序号 ,默认生成 2 个文件 ib_logfile0 和 ib_logfile1;
固定大小的文件,追加写入到文件末尾,会循环覆盖旧日志
内容
记录的是 数据页的物理修改 ,循环写
比如:表 t 的数据页 10 中,偏移量 50 的值从 10 改成 20
而非 SQL 逻辑
因此恢复时无需解析 SQL,直接应用数据页修改,速度极快
刷盘策略
核心控制参数:innodb_flush_log_at_trx_commit
取值有 0、1、2 三种,默认值为 1(强可靠性优先)
0 事务提交时不刷盘,由 InnoDB 后台线程每秒刷盘,可能丢失 1 秒内的已提交数据非核心业务(如日志存储、测试环境)
1(默认,最安全):事务提交时,强制刷盘(fsync),确保 redo log 持久化;金融、支付等核心业务(需严格保证 ACID)
2:事务提交时,写入操作系统缓存(page cache),由操作系统每秒刷盘;大部分非核心业务(如电商普通订单、用户行为数据)
核心作用
两大核心作用: 保证事务持久性 + 提升写入性能
如何保证事务持久性?
事务提交后,redo log 会先记录 数据页要做什么修改
再异步刷新数据文件(.ibd)
崩溃后可通过 redo log 恢复未刷盘的修改
如何提升写入性能?
数据修改时,若直接刷写数据文件(.ibd),会产生大量随机 IO(速度慢);
为何 会产生 随机 IO 呢? 因数据页在磁盘上分散存储,查找也费力~
而 redo log 是 顺序 IO
只需先将修改记录到 redo log
数据页(脏页)可后续由后台线程批量刷新,极大提升写入吞吐量
顺序 IO 和随机 IO 有什么区别?
顺序 IO 顾名思义,连续地址读写 ,无跳转
而随机 IO 离散地址读写,频繁跳转
机械硬盘 相差 10~100 倍,顺序读写≈100MB/s+,随机 IO 常 < 1~10MB/s
固态硬盘 相差 2~10 倍,顺序≈500MB/s~1GB/s,随机≈50~200MB/s
正常事务执行流程
假设执行 SQL:update t set a=20 where id=1;
正常流程:
读取数据到内存 InnoDB 从磁盘读取 id=1 对应的 data page(数据页)到 Buffer Pool
修改内存数据页在 Buffer Pool 中修改数据页的 a 值(从 10→20),此时数据页成为脏页
记录 redo log 到内存缓冲区生成一条 redo log 记录包含:数据页地址、偏移量、修改前值、修改后值、事务 ID 等)写入 redo log buffer
刷 redo log 到磁盘根据刷盘策略(由 innodb_flush_log_at_trx_commit 控制)将 redo log buffer 中的内容刷到磁盘的 redo log 文件
事务提交成功 redo log 刷盘完成后,事务返回 提交成功,不关注脏页是否刷盘
后台异步刷脏页 InnoDB 的 master thread 等后台线程,会在空闲时(如 Buffer Pool 满、系统负载低)double write 机制 保证 InnoDB 数据页的完整性将 Buffer Pool 中的脏页批量刷新到数据文件(.ibd)
什么是 double write 机制?跟着强子仔细研究一下:
double write 机制
触发时机
属于 Buffer Pool 中的脏页批量刷新到数据文件(.ibd)
触发场景
后台线程主动刷脏:InnoDB 的 master thread 等后台线程,在空闲时(如系统负载低)批量刷新 Buffer Pool 中的脏页;
Buffer Pool 满时刷脏:新数据页需加载到 Buffer Pool,而空间不足时,会淘汰旧脏页并触发刷盘;
手动触发刷脏:执行 flush tables、alter table 等语句,或设置 innodb_max_dirty_pages_pct 阈值触发;
Checkpoint 触发:InnoDB 的 Checkpoint 机制(如 Sharp Checkpoint、Fuzzy Checkpoint)触发脏页批量刷盘
工作流程
内存数据页修改:事务执行时,Buffer Pool 中的数据页被修改为脏页;
写入 double write buffer:脏页刷盘前,先将完整的数据页写入内存中的 double write buffer(全局共享缓冲区);
刷盘到 double write 文件:将 double write buffer 中的数据页批量刷盘到磁盘上的「double write 文件」(ibdata1 中或独立表空间),此过程为顺序写,性能高效;
刷盘到数据文件:确认 double write 文件写入成功后,再将数据页刷盘到实际的 .ibd 数据文件(随机写,因数据页分散存储);
崩溃恢复流程:数据页部分写入,异常中断,重启时 InnoDB 会:检测到 .ibd 中的损坏数据页;从 double write 文件中读取该页的完整备份,覆盖损坏页;通过 redo log 对该完整页应用未完成的修改,最终恢复数据一致性。
崩溃恢复流程
触发时机:在 事务提交成功 后 ,后台异步刷脏页 前,发生故障崩溃(脏页未刷盘)
重启时触发恢复:
InnoDB 启动时,扫描 redo log 文件组;
过滤出 已提交事务的 redo log 记录,通过事务 ID 区分,未提交事务的记录忽略
将这些记录对应的修改,重新应用到对应的数据页
应用完成后,删除已失效的 redo log 记录(已刷盘的记录),恢复完成
特点
是 InnoDB 独有的事务日志 ,二进制格式 的日志,非明文 SQL 或文本。
采用预写日志(WAL 机制)方式
崩溃安全(Crash-Safe)无论正常关闭还是异常崩溃,InnoDB 重启时都会扫描 redo log 将 已记录但未刷到数据文件 的修改重新应用到数据页,保证数据一致性
与事务绑定每个 redo log 记录都包含事务 ID(XID)已提交事务的修改会最终保留,未提交事务的 会在崩溃恢复时会被忽略
上文提到 WAL 机制 ,什么是 WAL 预写日志呢?
不用急,跟着强子的脚步继续探寻~
WAL
特点
修改数据前,必须先将 数据修改记录 写入日志
日志刷盘持久化后,再修改内存中的数据页;
后续数据页会异步、批量刷到磁盘(.ibd 文件)
简单来说: 日志先行,数据后写,日志是数据修改的 前置保障
作用
保证 crash-safe : 崩溃不丢数据
极大提升写入性能 : 顺序 IO VS 随机 IO
减少**刷盘开销: **不用每次修改都立即刷数据页到磁盘, 并且是批量,减少 IO 次数
binlog
由 MySQL 服务器(Server 层)生成,而非存储引擎,因此支持所有存储引擎
文件格式 & 内容
格式
以文件组形式存储(默认 mysql-bin.000001、mysql-bin.000002...)
按配置自动轮转,不会覆盖旧日志,需手动清理或设置过期时间
内容
记录的是数据修改的逻辑操作,而非物理地址修改
刚好 redo log 物理日志相反
仅记录已提交事务的操作(未提交事务不会写入 binlog)
具体格式分三种:
STATEMENT 格式记录执行的 SQL 语句(如 update t set a=20 where id=1)**有 SQL 歧义, **有可能 id =1 的数据不存在
ROW 格式(默认推荐)记录行数据的变更前后状态(如「id=1 的行,a 从 10 改成 20」)无 SQL 歧义,复制更精准;
MIXED 格式自动切换 STATEMENT/ROW 格式简单 SQL 用 STATEMENT,复杂 SQL 用 ROW
刷盘策略
控制 binlog 从内存(binlog cache)刷到磁盘的时机:
sync_binlog=0(默认):由操作系统决定刷盘时机(可能丢失未刷盘的 binlog);非核心业务(如日志存储、测试环境、内部管理系统)
sync_binlog=1(生产推荐,最安全):事务提交时强制刷盘,确保 binlog 持久化;金融、支付、核心交易业务
sync_binlog=N(N>1):累计 N 个事务后批量刷盘(平衡性能与安全性)高并发写入的普通业务
核心作用
主从复制
主库的 binlog 记录所有数据修改操作
从库通过复制主库的 binlog 并执行,实现主从数据一致
是 MySQL 读写分离、负载均衡、高可用架构(如 MGR、主从切换)的基础
时间点恢复
当数据发生误操作(如误删表、误更新)时,
可通过「全量备份 + binlog 增量恢复」
将数据恢复到误操作前的任意时间点,避免数据丢失
补充事务一致性
与 redo log 通过「两阶段提交」协作,确保主从复制时 binlog 与 redo log 数据一致,避免主从数据差异
上面提到的时间点恢复具体步骤是怎么样的呢?两阶段提交又是怎么回事?
通过 binlog 如何恢复数据?
两阶段提交是怎么回事?
跟强子学习一下,有备无患,说不定哪天就用上了~
binlog 恢复增量数据
核心前提
MySQL 已开启 binlog(必须,增量恢复依赖 binlog 记录变更);
存在一份 有效全量备份(备份时记录了对应的 binlog 文件名和位置,作为增量恢复的起点);
binlog 日志文件未被删除 / 覆盖(需提前配置 binlog 保留策略)
记得检查生产环境是否都符合~不然神仙难救~~
核心逻辑
本质是:用全量备份恢复到某个 基准时间点,
再通过 binlog 重放该时间点之后的所有数据变更(增删改)
最终恢复到目标状态
前期准备
环境说明
MySQL 版本:5.7/8.0(兼容);
目标数据库:test_db(需恢复的数据库);
全量备份工具:MySQL 自带 mysqldump(无需额外安装,最常用);
增量恢复工具:MySQL 自带 mysqlbinlog(解析 binlog 并执行恢复)。
如何确认 binlog 已开启?
未开启 binlog?如何配置?
编辑 MySQL 配置文件 my.cnf
重启 MySQL 生效
完整恢复流程
时间线是怎么样的?
T0(10:00):全量备份 test_db 数据库(基准备份);
T1(10:00~14:00):执行一系列数据变更(插入、更新数据);
T2(14:00):误操作删除 test_db.test_table 表,需恢复到 T2 之前的状态
操作步骤是怎么样的?
先删除损坏的数据库(避免冲突,谨慎操作!),记得备份做好
接着准备好恢复资料:
确定 全量备份 sql 文件 比如 test_db_full_20251201_1000.sql
执行全量备份 sql ,验证全量恢复结果
T0 前的 2 条数据
T1 的变更未恢复
提取增量 binlog
需要找到对应的最后执行的 sql 定位所在的 binlog,比如 binlog.000005
确定备份对应的 binlog 位置:154(增量恢复需从该位置开始)
查看 binlog 日志,找到 “误操作前的终点位置”
输出示例
增量恢复的起点:154(全量备份对应的位置);
增量恢复的终点:359(误操作 drop table 之前的位置)
应用增量 binlog 恢复
使用 mysqlbinlog 命令解析并执行增量部分的 binlog
验证恢复结果,看结果是否恢复到误操作前的状态
关键工具与命令汇总
注意事项
binlog 必须开启且格式为 ROW:避免使用 STATEMENT 格式(可能因 SQL _mode 差异导致恢复失败);查看格式:show variables like 'binlog_format';,需设为 ROW。
全量备份需记录 binlog 位置:必须加 --master-data=2 参数,否则无法确定增量恢复的起点;若备份时未加该参数,需通过 show master status 手动记录备份时的 binlog 文件名和位置。
binlog 文件不能丢失:配置 expire_logs_days 保留足够长时间的 binlog(如 7~30 天);重要场景可定期归档 binlog 到异地存储。
恢复前备份当前数据:恢复前若数据库仍有残留数据,建议先备份(如 mysqldump -u root -p --databases 库名 > 临时备份.sql),避免恢复失败导致数据二次丢失。
大事务处理:若增量 binlog 包含大事务,恢复时可能占用较多资源,建议在业务低峰期执行。
两阶段提交
是协调 redo log 和 binlog 一致性的核心机制
事务提交时,redo log 的写入会拆成两个阶段,而非一次性提交,最终保证两个日志的记录完全同步
具体过程
第一阶段做了什么操作?
事务执行完所有 SQL,InnoDB 写入该事务的所有 redo log 记录
把 redo log 的状态标记为 Prepare(准备就绪);
此时事务未真正提交,redo log 已持久化,但 binlog 还没写
第二阶段做了什么操作?
Server 层写入该事务的 binlog,并刷盘持久化;
将 redo log 的状态从 Prepare 改为 Commit;
事务正式提交完成
两阶段提交的原因
MySQL 中 redo log 和 binlog 是 两个独立的日志系统,用途不同但必须保持一致:
redo log:InnoDB 层的物理日志,用于崩溃恢复(保障 crash-safe);
binlog:Server 层的逻辑日志,用于主从复制、数据备份恢复
如果不做两阶段提交,直接 一次性写日志,会出现两种致命的不一致场景:
场景 1:先写 redo log,再写 binlog(宕机在 binlog 写入前)
结果:redo log 已记录事务,但 binlog 没记录该事务;
问题主从复制时,从库没同步到这个事务,导致主从数据不一致;用 binlog 备份恢复时,也会丢失该事务
场景 2:先写 binlog,再写 redo log(宕机在 redo log 写入前)
结果:binlog 已记录事务,但 redo log 没记录;
问题崩溃恢复时,InnoDB 找不到该事务的 redo log,会回滚事务,导致主库数据丢失但从库 / 备份有该数据,依然不一致
结论:两阶段提交的核心目的,是让 redo log 和 binlog 要么 都成功写入,要么 都不写入,避免因宕机导致的双日志不一致
binlog 与 redo log 差异
undo log
是 ACID 中的 A ,原子性
文件格式 & 内容
物理存储
InnoDB 引擎层的 逻辑日志 ,二进制内容
它没有独立的 专属文件,而是嵌入在 InnoDB 表空间中
共享表空间(默认,MySQL 5.7 及之前):存储在 ibdata1 文件中(与数据字典、undo 段、临时表空间等共用);
独立 undo 表空间(推荐,MySQL 8.0 默认开启)通过参数 innodb_undo_tablespaces 配置,生成独立文件 undo_001、undo_002(默认 2 个,可扩展),存储路径由 innodb_undo_directory 指定(默认与 datadir 一致)
逻辑存储结构
undo log 在表空间中以 段 - 区 - 页 的层级结构存储:
undo 段(Undo Segment):每个事务会分配一个或多个 undo 段,用于存储该事务的所有 undo 记录;
undo 页(Undo Page):undo 段由多个连续的数据页组成(默认页大小 16KB),undo 记录按顺序追加写入;
回滚段(Rollback Segment):InnoDB 默认有 128 个回滚段(参数 innodb_rollback_segments 控制),每个回滚段可管理多个 undo 段,用于复用资源、减少碎片
特性
undo log 是 循环写入、可回收 的:
事务提交后,undo log 不会立即删除(MVCC 可能需要读取历史版本);
当 undo log 对应的 历史版本 不再被任何事务引用时,InnoDB 的 purge 线程会异步清理这些过期 undo 记录,释放页空间供新事务复用;
内容
核心元数据
事务 ID(TRX_ID):所属事务的唯一标识,用于关联事务和 undo 记录;
回滚指针(ROLL_PTR):指向当前记录的上一个版本的 undo 记录(形成 “版本链”,支撑 MVCC 读取);
表 ID(TABLE_ID):标识操作的目标表(InnoDB 内部表唯一标识,非用户可见的表名);
操作类型(OP_TYPE):标记操作类型(如 INSERT、UPDATE、DELETE);
主键 / 唯一键信息:定位被操作的行(如主键值,用于精准回滚时找到目标记录)
不同操作的 undo 记录内容
INSERT 核心内容:仅记录 插入行的主键值(无需记录其他字段);回滚逻辑:根据主键直接删除这条插入的行特点:事务提交后,这类 undo 记录最容易被 purge 清理
UPDATE 核心内容:记录 被修改字段的 “旧值”(仅修改前的原始值,不记录新值)+ 主键;回滚逻辑:用旧值覆盖当前字段的新值,恢复到修改前状态
DEL 核心内容:记录 被删除行的完整字段值(所有列的原始数据)+ 主键;回滚逻辑:重新插入这条完整记录注意:InnoDB 的 DELETE 是 标记删除(逻辑删除),事务提交后,该行不会立即从数据页中物理删除,而是等待 purge 线程根据 undo log 清理
工作流程
undo log 的工作流程
事务执行时生成
事务回滚时应用
MVCC 读时遍历
过期后清理
四个核心环节展开
InnoDB 表的每行数据默认包含三个隐藏字段,为 undo log 提供基础:
DB_TRX_ID:记录最后修改该行的事务 ID;
DB_ROLL_PTR:指向该行对应的 undo log 记录(版本链指针);
DB_ROW_ID:若表无主键或唯一索引,自动生成的行唯一标识
事务执行时
假设执行事务 (初始 id=1 的行 a=10)
事务启动,分配唯一事务 ID(如 trx_id=100)
第一次 update(a=10→20)读取 id=1 的数据页到 Buffer Pool;生成一条 undo log 记录(类型:UPDATE,包含旧值 a=10、DB_TRX_ID=100、上一版本指针 null);将该 undo log 写入 undo 表空间(同时生成 redo log 记录 undo log 的修改,确保持久化);更新数据行的 DB_TRX_ID=100,DB_ROLL_PTR 指向刚生成的 undo log 记录;修改内存数据页的 a 值为 20(脏页)
第二次 update(a=20→30)生成新的 undo log 记录(类型:UPDATE,包含旧值 a=20、DB_TRX_ID=100、上一版本指针→第一次的 undo log 记录);写入 undo 表空间并记录 redo log;更新数据行的 DB_ROLL_PTR 指向本次的 undo log 记录;修改内存数据页的 a 值为 30(脏页)
此时,id=1 行的版本链为:数据页当前值(a=30,trx_id=100)→ undo log2(a=20)→ undo log1(a=10)
事务回滚时
若上述事务执行第二次 update 后,因业务错误执行 rollback;
InnoDB 读取该事务生成的所有 undo log 记录(按生成顺序反向遍历:先 undo log2,再 undo log1);
应用 undo log2:将数据行的 a 值从 30 改回 20;
应用 undo log1:将数据行的 a 值从 20 改回 10;
清空该事务的 undo log 标记(后续由 purge 线程清理);
事务回滚完成,数据恢复到事务开始前的状态(a=10)
MVCC 读时
假设事务 A(trx_id=200)在事务 B(trx_id=100)执行 update 期间,以「可重复读」隔离级别读取 id=1 的行:
事务 A 启动时,InnoDB 会记录当前 活跃事务 ID 列表(此时包含 trx_id=100);
事务 A 读取 id=1 的数据行,发现其 DB_TRX_ID=100, 属于活跃事务,不可直接读取;
通过 DB_ROLL_PTR 遍历版本链,找到上一版本的 undo log2(trx_id=100,仍活跃);
继续遍历到 undo log1(trx_id=100,仍活跃,不可直接读取)
再往上得到初始版本,无事务 ID,确认初始版本(a=10)对事务 A 可见(无冲突),返回 a=10 给事务 A
即使事务 B 后续提交(trx_id=100 变为非活跃),事务 A 再次读取时,仍通过版本链找到初始版本 a=10,保证 可重复读
undo log 清理
事务提交后,其生成的 undo log 被标记为 过期(但不会立即删除,因为可能有其他事务在读取该版本链);
InnoDB 的 purge 线程是后台线程,定期扫描 undo 表空间,筛选出 所有活跃事务都不再访问 的过期 undo log
删除这些 undo log 记录,释放 undo 表空间的存储空间,实现循环复用
核心作用
保证事务原子性
事务执行过程中,若发生错误(如 SQL 执行失败、手动 rollback、系统崩溃)
可通过 undo log 撤销事务已执行的修改,恢复到事务开始前的状态
确保事务 要么全做,要么全不做
支撑 MVCC
为读取操作提供 历史数据版本:当其他事务修改了数据,当前事务可通过 undo log 遍历历史版本链,读取到事务开始前或指定版本的数据实现 读不加锁、写不阻塞读的并发控制避免脏读、不可重复读
mvcc
MVCC(Multi-Version Concurrency Control,多版本并发控制)
是一个机制
是 InnoDB 存储引擎的核心并发控制机制
核心定位:在不依赖悲观锁的前提下,实现 读不加锁、写不阻塞读 的高并发读写
其底层依赖
undo log 构建的版本链
事务 ID 机制
核心作用
解决读写冲突
MVCC 通过提供数据的 历史版本,让读操作访问旧版本、写操作修改新版本
保障事务隔离性
ACID 中的 I
是 InnoDB 实现「读已提交(RC)」和「可重复读(RR)」的核心技术:读已提交(RC):每次查询都获取最新的 “已提交事务版本”,避免脏读;可重复读(RR):事务启动时生成数据快照,后续查询仅访问该快照,避免脏读和不可重复读
避免脏读、不可重复读
通过版本链筛选 对当前事务可见的数据版本,
读操作不会获取未提交事务的修改(避免脏读),
同一事务内多次读取结果一致(避免不可重复读)
核心特点
非阻塞读(快照读)
普通查询(如 select * from t where id=1)属于快照读,无需加锁,直接通过版本链获取历史数据,不会阻塞写操作;
同时写操作也不会阻塞快照读
什么是快照读?什么是当前读?
快照读:普通 select(不加锁),基于 MVCC 访问历史版本,非阻塞;
当前读加锁查询(如 select ... for update)、update、delete、insert,访问数据的最新版本,需加锁保证原子性,会阻塞其他写操作
基于版本链实现
依赖于
InnoDB 数据行的隐藏字段(DB_TRX_ID、DB_ROLL_PTR)
undo log 构建 版本链
最新数据存储在数据页,历史版本串联在 undo log 中,读操作通过遍历版本链找到可见版本
事务快照(Read View)
每个事务启动时(或查询时,因隔离级别而异)会生成一个「Read View(读视图)」
Read View 是判断版本可见性的依据,包含 4 个关键信息:
m_ids:当前活跃的事务 ID 列表(未提交的事务);
min_trx_id:活跃事务 ID 中的最小值;
max_trx_id:当前已分配的最大事务 ID + 1(下一个要分配的事务 ID);
creator_trx_id:生成该 Read View 的事务 ID(当前事务 ID)。
工作流程
遍历版本链时,通过数据版本的 DB_TRX_ID(修改该版本的事务 ID)与 Read View 对比,判断是否可见
若 DB_TRX_ID == creator_trx_id:当前事务修改的版本,可见;
若 DB_TRX_ID < min_trx_id:修改该版本的事务已提交(早于所有活跃事务),可见;
若 DB_TRX_ID >= max_trx_id:修改该版本的事务是未来启动的(晚于当前 Read View 生成),不可见;
若 min_trx_id <= DB_TRX_ID < max_trx_id:若 DB_TRX_ID 在 m_ids 中(事务未提交),不可见;若 DB_TRX_ID 不在 m_ids 中(事务已提交),可见;
若当前版本不可见,通过 DB_ROLL_PTR 遍历上一个版本,重复上述判断,直到找到可见版本(或版本链结束,返回空)
不同隔离级别的流程差异
可重复读
事务启动时生成一次,整个事务生命周期内复用该 Read View
流程示例
事务 A(trx_id=100)启动,生成 Read View:m_ids=[100],min_trx_id=100,max_trx_id=101;
事务 B(trx_id=101)启动,执行 update t set a=20 where id=1(初始 a=10),提交;
事务 A 执行 select a from t where id=1:数据页当前版本 DB_TRX_ID=101,判断:101 >= max_trx_id(101),不可见;遍历 undo log 找到上一版本(a=10,DB_TRX_ID=0,初始版本);0 < min_trx_id(100),可见,返回 a=10;
事务 A 再次查询,仍复用同一个 Read View,返回 a=10(可重复读)
读已提交
Read View 生成时机:每次执行查询时生成新的 Read View;
流程示例
事务 A(trx_id=100)启动,第一次查询 select a from t where id=1:生成 Read View:m_ids=[100],min_trx_id=100,max_trx_id=101;数据页版本 DB_TRX_ID=0,可见,返回 a=10;
事务 B(trx_id=101)启动,执行 update t set a=20 where id=1,提交;
事务 A 第二次查询 select a from t where id=1:生成新的 Read View:m_ids=[100],min_trx_id=100,max_trx_id=102;数据页当前版本 DB_TRX_ID=101,判断:101 不在 m_ids 中(事务 B 已提交),可见;返回 a=20(读已提交,每次查询获取最新已提交版本)
当前读的处理逻辑
当前读(select ... for update、update、delete 等)不依赖 MVCC 的快照,而是直接访问数据的最新版本,同时加行锁 / 表锁保证原子性:
执行当前读时,先获取目标数据行的排他锁(或共享锁),阻塞其他写操作;
直接读取数据页的最新版本(忽略历史版本);
执行修改操作后,更新数据行的 DB_TRX_ID 和 DB_ROLL_PTR,生成新的 undo log 记录,更新版本链。
总结
这次解析了与 日志 相关的很多知识点:
redo log /undo log / binlog
两阶段提交 /double write /write-aheard-logging (WAL)
MVCC
不单单分析了日志的内容,格式,甚至还介绍了一下数据恢复的方法~
深入研究底层原理,未来解决问题会更精准~
熟练度刷不停,知识点吃透稳,下期接着练~
版权声明: 本文为 InfoQ 作者【DonaldCen】的原创文章。
原文链接:【http://xie.infoq.cn/article/be323e0d9b5794f548bd5d19c】。文章转载请联系作者。







评论