为什么MySQL默认使用可重复读RR?深入解析binlog与隔离级别的关系
在面试MySQL事务隔离级别时,很多同学会背出四个级别:读未提交RU、读已提交RC、可重复读RR、可串行化Serializable。
但是很少有人知道:
为什么MySQL默认不是RC(读已提交),而是RR(可重复读)?
更少人知道这背后与binlog的格式兼容性有直接关系。
今天程序员卷卷狗就带你彻底搞懂这个问题,让你在面试中一招制胜。
一、背景:MySQL为什么要有binlog?
MySQL的主从复制依赖binlog。
binlog主要有两种格式:
- statement格式:记录SQL文本
- 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隔离级别下执行事务:
- T1开始事务,第一次读余额=1000
- 另一事务把余额改成2000并提交
- T1第二次读余额=2000
- 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更强,而是因为:
- 早期MySQL大量使用statement格式binlog
- statement格式记录的是SQL不是执行结果
- RC允许每次读取不同版本的数据
- 主从在重放SQL时可能读取到不同快照
- 最终导致主从数据不一致
RR通过一致性视图保证事务中读取的数据稳定,
使得主从在重放binlog时能得到一致结果。
因此:
MySQL为了兼容statement格式binlog并避免主从不一致,选择RR作为默认隔离级别。
七、卷卷的今日感悟
今天明白了,原来很多我们习以为常的默认值,都不是随便定的,而是MySQL在无数实际问题里打滚打出来的经验。
以前总觉得这些东西离我很远,但真正遇到主从不一致、顺着binlog追原因的时候,才发现理解原理才是真正的基石。
程序员卷卷狗的今日八股分享到此为止。
感兴趣的朋友可以关注私聊我 一起加油学习~