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

MySQL 5.7 和 8.0 的默认事务隔离级别都是 REPEATABLE-READ,且 SELECT @@transaction_isolation 返回值完全一致。这不是“兼容性保留”,而是 InnoDB 强制实现的底层行为——没变,但执行时更较真了。
查隔离级别时为什么 @@transaction_isolation 在 5.7/8.0 能用,但在 5.6 就报错?
变量名随版本演进:tx_isolation 是 MySQL 5.6 及更早的系统变量;transaction_isolation 从 5.7 开始引入并成为唯一标准。若你在 5.6 环境执行 SELECT @@transaction_isolation,会直接报错 Unknown system variable 'transaction_isolation'。
- 安全写法是先确认版本:
SELECT VERSION() - 跨版本兼容查询建议:用
SELECT @@SESSION.tx_isolation, @@SESSION.transaction_isolation,任一返回非 NULL 即有效 - 注意返回值格式是
'REPEATABLE-READ'(短横线),不是下划线或小写
REPEATABLE-READ 没变,但为什么升级后事务突然卡住或报死锁?
不是隔离级别变了,是 InnoDB 锁实现收紧了。关键变化点有三个:
-
innodb_locks_unsafe_for_binlog在 8.0 彻底移除 → 所有SELECT FOR UPDATE都严格走 Next-Key Lock,不再退化为仅记录锁 - 隐式类型转换(如
WHERE varchar_id = 123)在 8.0 更早放弃索引 → 触发全表扫描 + 全表锁升级,而 5.7 可能侥幸走索引少锁 - MDL(元数据锁)策略收紧 → 一个
ALTER TABLE就能让正在跑的REPEATABLE READ事务卡在Waiting for table metadata lock
改隔离级别能缓解阻塞吗?哪些场景真有用
把默认 REPEATABLE-READ 改成 READ-COMMITTED 确实能降低间隙锁范围、减少幻读相关阻塞,但必须满足前提:
- binlog 格式必须是
ROW(现在主流都已是,但老系统要确认) - WHERE 条件必须命中索引,否则
READ-COMMITTED下连行锁都不加,反而放大并发问题 - 连接池需重建 ——
SET GLOBAL不影响已存在的连接,Druid/Hikari 等池子可能缓存旧会话,得滚动重启或设初始化 SQL
真正容易被忽略的是:哪怕你把全局设成 READ-COMMITTED,只要某段代码里写了 START TRANSACTION 却没显式指定级别,它仍继承会话当前值;而 ORM 框架(如 MyBatis)生成的 SQL 很可能不带 FOR UPDATE,导致你以为加了锁,其实什么都没锁。











