mysql 8.0默认事务隔离级别仍是repeatable read,这是为保障主从复制正确性、mvcc逻辑及存量业务快照读依赖而主动维持的设计决策,非历史遗留;其通过间隙锁与一致性快照规避statement格式binlog下的主从不一致风险,并在8.0中强化了锁行为与mdl策略。

MySQL 8.0 中默认事务隔离级别仍是 REPEATABLE READ,这不是版本迭代时“忘了改”,而是设计上主动维持的兼容性决策——它背后绑着主从复制正确性、MVCC 实现逻辑、以及大量存量业务对快照读行为的隐式依赖。
为什么不能随大流改成 READ COMMITTED?
Oracle、PostgreSQL、SQL Server 默认用 READ COMMITTED,但 MySQL 不能简单照搬。核心矛盾在 binlog 复制机制:
- MySQL 主从复制长期依赖
STATEMENT格式 binlog(直到 5.1 才支持ROW),而该格式下READ COMMITTED会导致主从不一致:同一事务内语句执行顺序与 binlog 记录顺序可能错位,从库重放时结果不同; -
REPEATABLE READ引入间隙锁(Gap Lock)和一致性快照,让主库在事务开始时就“锁定范围”,天然规避了语句重排引发的复制偏差; - 即使现在默认 binlog 是
ROW,MySQL 仍需向后兼容大量使用STATEMENT或MIXED的老系统,改默认级别会直接触发线上主从断裂风险。
MySQL 8.0 对 REPEATABLE READ 的底层强化
8.0 没降低隔离级别,反而收紧了它的行为边界——不是“变严了”,而是“原来没管住的现在管住了”:
-
innodb_locks_unsafe_for_binlog参数在 8.0 中被彻底移除,意味着所有SELECT ... FOR UPDATE和SELECT ... LOCK IN SHARE MODE都强制走索引加锁(含间隙锁),不再退化为仅锁记录; - 隐式类型转换导致的索引失效场景下,8.0 的锁范围判断更精确,以前可能漏锁的间隙,现在大概率被锁住;
- MDL(Metadata Lock)策略收紧,事务持有表元数据锁的时间更长、粒度更细,间接强化了
REPEATABLE READ下 DDL 与 DML 的互斥性。
你查到的 @@transaction_isolation 真的可靠吗?
执行 SELECT @@transaction_isolation 返回 REPEATABLE-READ,只说明会话级变量值是这个,不代表当前事务实际行为完全等同于教科书里的 RR:
- 如果事务里混用了
READ COMMITTED级别的语句(比如显式加锁查询),InnoDB 会按语句粒度动态调整锁策略; - 只读事务(无写操作)在 8.0 中可能跳过部分 MVCC 版本链遍历,快照生成逻辑与传统 RR 有细微差异;
- 开启
binlog_format=ROW+innodb_foreach_row_locks=ON时,某些压测工具看到的“幻读消失”,其实是锁行为变化掩盖了 MVCC 层面的语义边界。
真正容易被忽略的点是:MySQL 的 REPEATABLE READ 从来就不是 SQL 标准的严格实现,它用 MVCC + 间隙锁组合出一个“够用且可控”的工程解。升级到 8.0 后,别只盯着 SELECT @@transaction_isolation 的输出,得去验证你业务中最关键的那几条 SELECT 是否还在预期快照里——尤其是带范围条件、ORDER BY LIMIT、或嵌套子查询的语句。











