mysql默认隔离级别为repeatable-read;查会话级用select @@transaction_isolation(8.0+)或@@tx_isolation(5.7-),查全局级须加@@global.前缀,旧版本不支持transaction_isolation变量名。

REPEATABLE-READ 是 MySQL 默认且最稳妥的选择,绝大多数 OLTP 场景无需修改;只有在明确容忍“不可重复读”、且存在高并发读多写少瓶颈时,才考虑降级为 READ COMMITTED。
怎么看当前会话和全局的隔离级别?
直接查 @@transaction_isolation 只反映当前会话值,它可能已被 ORM 或连接池覆盖;必须同时查 @@global.transaction_isolation 才知道 MySQL 启动时的真实默认配置。
旧版本(如 5.6)不支持 transaction_isolation,只认 tx_isolation,安全写法是:
SELECT @@transaction_isolation, @@tx_isolation;
返回值是带连字符的字符串,例如 'REPEATABLE-READ',空格或引号会导致解析失败。
如果任一字段返回 NULL 或空字符串,不是“没设置”,而是配置语法错误或未生效。
为什么 SET SESSION TRANSACTION ISOLATION LEVEL 总报错?
最常见错误:在事务已开启后尝试修改级别。一旦执行过 START TRANSACTION 或第一条 DML,再执行 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED 就会立刻报错:
Can’t change transaction isolation level when a transaction is active
ORM 框架(如 Spring 的 @Transactional)常在方法入口自动启事务,此时再 set 已经晚了。
- 正确时机:连接刚建立、尚未执行任何 SQL 时,或显式
START TRANSACTION之前 - 可行方案:在连接池的
initSql中预设,例如SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED - 避免在长连接中反复切换,尤其不能在事务内嵌套修改
全局改 READ COMMITTED 为什么没效果?
SET GLOBAL transaction_isolation = 'READ-COMMITTED' 只影响后续新建连接,已有活跃会话完全不受影响。
该命令不持久化,MySQL 重启即失效。要永久生效,必须编辑配置文件:
- Linux:
/etc/my.cnf或/etc/mysql/my.cnf,在[mysqld]下加transaction-isolation = READ-COMMITTED - Windows:
my.ini同样位置 - 注意:连字符不能写成下划线,不能加引号或空格,否则 MySQL 启动失败
- 修改后必须重启 mysqld 进程,
FLUSH PRIVILEGES或SIGHUP无效
云数据库(如阿里云 RDS)通常禁用 SET GLOBAL,只能通过控制台修改参数组并重启实例。
REPEATABLE-READ 真的会幻读?什么时候需要干预?
InnoDB 的 REPEATABLE-READ 实际通过 Next-Key Lock(行锁 + 间隙锁)拦截大部分幻读,但仅对 WHERE 条件能命中索引的路径有效。
全表扫描、或范围查询未覆盖的间隙(比如 WHERE status = 'pending' 不会锁住 status = 'shipped' 的间隙),其他事务仍可插入新行。
若业务真需杜绝幻读,不要盲目升到 SERIALIZABLE——它会锁整张表,性能断崖下跌。优先考虑:
- 在关键查询后加
SELECT ... FOR UPDATE显式加锁 - 优化索引,让 WHERE 条件尽可能走索引覆盖
- 用唯一约束或应用层幂等控制代替强一致性要求
真正需要调隔离级别的场景极少,多数性能问题出在慢查询、缺失索引或连接池配置,而非 REPEATABLE-READ 本身。











