MySQL默认事务隔离级别是REPEATABLE READ,由InnoDB强制实现;查级别需按版本选变量(5.7+用transaction_isolation,5.6-用tx_isolation);改级别分SESSION、GLOBAL、配置文件三类作用域;大厂常切READ COMMITTED以降锁、减阻塞、合直觉,但须验证业务兼容性。

MySQL 默认事务隔离级别是 REPEATABLE READ(可重复读),由 InnoDB 存储引擎强制实现,且自 MySQL 5.1 起成为全局默认值。这不是配置出来的“习惯”,而是底层 MVCC + 间隙锁协同保障主从一致性的硬性设计结果。
怎么查当前隔离级别?别用错变量名
不同 MySQL 版本使用不同系统变量,混用会导致查不到或报错:
- MySQL 5.7 及之后(含 8.0):用
@@transaction_isolation和@@GLOBAL.transaction_isolation - MySQL 5.6 及更早:用
@@tx_isolation和@@GLOBAL.tx_isolation
SELECT @@SESSION.transaction_isolation, @@GLOBAL.transaction_isolation;
如果返回类似 'REPEATABLE-READ'(注意是短横线而非下划线),说明生效;若返回空或报错 Unknown system variable,大概率版本不匹配,立刻切回 tx_isolation 查。
怎么改?session、global、配置文件三者效果完全不同
改隔离级别不是“设一次就永远生效”,必须分清作用域:
-
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;:只影响当前连接后续事务,断连即失效 -
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;:影响所有新建连接(已有连接不变),需 SUPER 权限,重启后丢失 - 在
/etc/my.cnf中写transaction-isolation = READ-COMMITTED:服务重启后对所有连接生效,但无法热加载
⚠️ 注意:GLOBAL 设置不会改变当前已存在的会话,线上调参前务必确认连接池是否复用旧连接——很多 Java 应用用 Druid/Hikari 连接池,改了 global 后新连接才走新级别,老连接仍卡在 REPEATABLE READ。
为什么大厂线上常改成 READ COMMITTED?不是默认就好吗
MySQL 默认选 REPEATABLE READ 是历史包袱:早期 binlog 格式只有 STATEMENT,配合 RC 会导致主从不一致(删/插顺序被重排)。但现在普遍用 ROW 格式 binlog,这个限制已解除。
改用 READ COMMITTED 的真实动因是:
- 降低锁粒度:
RC不用间隙锁(Gap Lock),高并发 INSERT 场景下死锁概率显著下降 - 减少长事务阻塞:
RR下一个长事务会 hold 住 MVCC 快照,导致 purge 线程无法清理旧版本,undo 表空间暴涨 - 语义更贴近直觉:开发者通常预期“只能读到已提交数据”,而不是“同一事务内反复读都一样”
但切换前必须验证:业务 SQL 是否依赖 RR 的可重复性?比如报表类任务在事务中多次 SELECT COUNT(*),换 RC 后可能因中间有其他事务提交而结果漂移。
真正容易被忽略的点是:隔离级别不是孤立参数,它和 binlog_format、innodb_lock_wait_timeout、甚至应用层重试逻辑强耦合。调之前先看慢日志里有没有大量 Lock wait timeout exceeded,再决定是调级别,还是优化 SQL 加索引,或者干脆加 SELECT ... FOR UPDATE 显式控制。










