mysql 8.0 并未改变 repeatable read 隔离级别语义,但因移除 innodb_locks_unsafe_for_binlog、强化 next-key lock、收紧 mdl 及默认开启死锁检测,导致锁行为更严格、阻塞与死锁更易暴露。

不是“更严谨”,而是原本被掩盖的锁行为和一致性边界,在 8.0 中不再容忍模糊地带——事务逻辑没变,但执行时更较真了。
REPEATABLE READ 隔离级别本身没变,但锁范围变实了
MySQL 8.0 仍默认用 REPEATABLE READ,SELECT @@transaction_isolation 返回值和 5.7 一致。问题出在 InnoDB 锁实现上:innodb_locks_unsafe_for_binlog 这个开关在 8.0 彻底移除,所有 SELECT FOR UPDATE 和 SELECT LOCK IN SHARE MODE 都严格按索引加 Next-Key Lock(记录锁 + 间隙锁),不再退化为仅记录锁。
- 5.7 中用非唯一索引字段做
UPDATE WHERE non_unique_col = ?,可能只锁命中行;8.0 默认锁整个间隙,高并发插入时容易阻塞 - 5.7 查询未命中行时,可能只锁索引项;8.0 直接锁该值对应间隙,后续相同条件的
INSERT会被卡住 - WHERE 条件含隐式类型转换(如
WHERE varchar_id = 123),8.0 优化器更早放弃索引、触发全表扫描+锁升级,而 5.7 可能侥幸走索引少锁
元数据锁(MDL)策略收紧,DDL 和事务更容易互等
MySQL 8.0 的原子 DDL 要求更强的 MDL,哪怕只是普通 REPEATABLE READ 事务,也可能被 ALTER TABLE 卡住更久。这不是事务隔离级别变了,而是 DDL 操作对元数据的独占性更高了。
- 常见现象:慢查询日志里大量
Waiting for table metadata lock,其实和事务隔离无关,是 DDL 正在执行时,监控脚本查sys.innodb_lock_waits被 MDL 卡住,拖慢连接池响应 -
SHOW ENGINE INNODB STATUS\G的TRANSACTIONS区段里,若看到事务长时间停留在ACTIVE状态且无 SQL 正在执行,大概率是被 DDL 阻塞,而非死锁
死锁检测默认开启,旧代码里的锁序混乱直接暴露
5.7 默认关闭 innodb_deadlock_detect(尤其高并发写场景常被手动关掉),而 8.0 默认为 ON。你不是遇到更多死锁,而是原来静默失败或重试绕过的场景,现在全被中止并报错。
- 错误日志里密集出现
Deadlock found when trying to get lock,先别调innodb_deadlock_detect=OFF,要确认是否两个事务总在相同表、相同条件、不同顺序下抢锁 - 用
SHOW ENGINE INNODB STATUS\G看TRANSACTIONS部分:事务 A 持有table_a行锁却等table_b,事务 B 持有table_b却等table_a→ 典型锁序不一致,得改应用层代码 - 批量更新用
IN (1,2,3,...1000)但没走索引,8.0 的间隙锁范围更大,多个事务扫同一区间极易形成循环等待
真正难处理的不是配置项变化,而是那些依赖 5.7 “宽松行为”的业务逻辑——它们在 8.0 下不是报错,就是阻塞或死锁,而且往往只在特定并发路径下才触发。











