为什么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追原因的时候,才发现理解原理才是真正的基石。

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

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

相关推荐
此生只爱蛋3 小时前
【Redis】String 字符串
java·数据库·redis
瀚高PG实验室3 小时前
拼接符“II”在Oracle和HGDB中使用的差异
数据库·oracle·瀚高数据库
心态还需努力呀3 小时前
当时序数据不再“只是时间”:金仓数据库如何在复杂场景中拉开与 InfluxDB 的差距
数据库
宇灬宇3 小时前
oracle误drop表,通过回收站恢复
数据库·oracle
Albert Tan3 小时前
Oracle EBS 12.2/12.1 开放本地或远程访问Weblogic
数据库·oracle
一个处女座的程序猿O(∩_∩)O3 小时前
从InfluxDB到金仓:时序数据库性能拐点已至?
数据库·时序数据库
数据和云3 小时前
Oracle没有退路
数据库·oracle·vr
Gauss松鼠会3 小时前
【openGauss】让gsql和sqlplus输出包含有SQL及数据的完全一致的文本文件
数据库·sql·database·opengauss
盛世宏博北京3 小时前
分布式库房集中管!云端 “八防” 监控平台,多站点统一可视化运维
大数据·网络·数据库·档案温湿度