为什么MySQL默认使用可重复读RR?深入解析binlog与隔离级别的关系

为什么MySQL默认使用可重复读RR?深入解析binlog与隔离级别的关系

在面试MySQL事务隔离级别时,很多同学会背出四个级别:读未提交RU、读已提交RC、可重复读RR、可串行化Serializable。

但是很少有人知道:

为什么MySQL默认不是RC(读已提交),而是RR(可重复读)?
更少人知道这背后与binlog的格式兼容性有直接关系。

今天程序员卷卷狗就带你彻底搞懂这个问题,让你在面试中一招制胜。


一、背景:MySQL为什么要有binlog?

MySQL的主从复制依赖binlog。

binlog主要有两种格式:

  1. statement格式:记录SQL文本
  2. row格式:记录行级数据变更结果

早期MySQL大量使用statement格式,因为它:

  • 更小
  • 更快
  • 占用更少磁盘

但是也因此带来了一个严重问题:

如果主从在执行同一条SQL时读到的数据不一样,就会导致主从结果不一致。

这就是RR默认级别的根因。


二、核心问题:为什么RC/RU会导致主从数据不一致?

先看statement格式binlog的一个特点:

binlog里记录的是SQL语句本身,而不是执行结果。

比如主库执行:

sql 复制代码
UPDATE account SET balance = balance - 100 WHERE id=1;

binlog中记录的就是这一条SQL。

从库重放时,会重新执行这条SQL

如果主库和从库执行时读到不同的数据,那么执行结果会不同,导致主从不一致。

问题就出在事务隔离级别。


三、隔离级别对主从一致性的影响(关键)

我们先快速复习三个级别的读行为:

隔离级别 多次读取行为
RU(读未提交) 可以读到未提交的数据(脏读)
RC(读已提交) 每次读到的都是最新提交版本
RR(可重复读) 事务内所有读基于同一份快照

关键点在于:

RC会让同一个事务多次读取"不同版本的数据"。
而RR保证整个事务始终读到"同一版本的数据"。

现在回到主从复制。


四、经典示例:RC导致的主从不一致

假设account表余额为1000。

主库在RC隔离级别下执行事务:

  1. T1开始事务,第一次读余额=1000
  2. 另一事务把余额改成2000并提交
  3. T1第二次读余额=2000
  4. T1执行更新:
sql 复制代码
UPDATE account SET balance = balance - 100 WHERE id=1;

此时主库结果是:

2000-100=1900

binlog中写入的仍然是statement:

复制代码
UPDATE account SET balance = balance - 100 WHERE id=1;

从库执行binlog时(快照不同)

从库可能读到的是1000(因为它是异步复制):

执行SQL后结果变成900。

最终结果:

节点 余额
主库 1900
从库 900

主从彻底不一致。

这问题就是因为:

  • RC隔离级别允许读到不同版本数据
  • statement格式binlog只记录SQL,不记录具体的值
  • 重放SQL时会基于从库当前版本再次计算

因此MySQL绝不能默认RC。


五、RR(可重复读)如何避免主从不一致?

RR在事务开始时创建一个一致性视图(snapshot)。

整个事务中:

  • 不管别人如何提交
  • 不管别人更新成多少
  • 当前事务读到的数据都是同一版本

回到上面例子:

T1第一次读到余额=1000

即使其他事务把余额改成2000

T1第二次读仍然是1000

所以主库执行 UPDATE 时:

1000-100=900

binlog重放时,从库也会读到同样的快照(或等价值),最终结果一致。

RR保证了主从执行SQL时使用一致的数据版本,使得statement格式binlog不会产生不一致。

这才是MySQL默认使用RR的真正原因。


六、卷卷总结

MySQL默认使用可重复读RR,不是因为RR比RC更强,而是因为:

  1. 早期MySQL大量使用statement格式binlog
  2. statement格式记录的是SQL不是执行结果
  3. RC允许每次读取不同版本的数据
  4. 主从在重放SQL时可能读取到不同快照
  5. 最终导致主从数据不一致

RR通过一致性视图保证事务中读取的数据稳定,

使得主从在重放binlog时能得到一致结果。

因此:

MySQL为了兼容statement格式binlog并避免主从不一致,选择RR作为默认隔离级别。


七、卷卷的今日感悟

今天明白了,原来很多我们习以为常的默认值,都不是随便定的,而是MySQL在无数实际问题里打滚打出来的经验。

以前总觉得这些东西离我很远,但真正遇到主从不一致、顺着binlog追原因的时候,才发现理解原理才是真正的基石。

程序员卷卷狗的今日八股分享到此为止。

感兴趣的朋友可以关注私聊我 一起加油学习~

相关推荐
霖霖总总1 小时前
[小技巧19]MySQL 权限管理全指南:用户、角色、授权与安全实践
数据库·mysql·安全
heartbeat..5 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
麦聪聊数据7 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
AC赳赳老秦8 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
myzshare9 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
YMatrix 官方技术社区9 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
辞砚技术录10 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
linweidong10 小时前
C++thread pool(线程池)设计应关注哪些扩展性问题?
java·数据库·c++
墨笔之风11 小时前
java后端根据双数据源进行不同的接口查询
java·开发语言·mysql·postgres
欧亚学术11 小时前
突发!刚刚新增17本期刊被剔除!
数据库·论文·sci·期刊·博士·scopus·发表