MySQL 8.0+ 全局事务隔离级别只能通过 my.cnf 配置并重启生效,SET GLOBAL 报错;会话级需用 SET SESSION transaction_isolation = 'READ-COMMITTED';默认 REPEATABLE-READ 含间隙锁,高并发下易锁争用。

MySQL 8.0+ 修改全局事务隔离级别必须改 my.cnf,SET GLOBAL 不生效
MySQL 8.0 开始,transaction_isolation 变成只读系统变量,SET GLOBAL transaction_isolation = 'READ-COMMITTED' 会直接报错:ERROR 1238 (HY000): Variable 'transaction_isolation' is a read only variable。这不是权限问题,是设计变更 —— 全局隔离级别只能靠配置文件启动时加载。
实操建议:
- 编辑
/etc/my.cnf(或/etc/mysql/my.cnf,取决于安装方式),在[mysqld]段落下加一行:transaction_isolation = READ-COMMITTED - 重启 MySQL:
sudo systemctl restart mysqld(或mysql.server restart) - 验证是否生效:
SELECT @@global.transaction_isolation;,注意必须用@@global,@@session默认继承全局值但可被会话覆盖
SET SESSION transaction_isolation 只影响当前连接,且语法因版本而异
5.7 和 8.0+ 都支持会话级修改,但写法不同:5.7 认可 SET SESSION tx_isolation = 'REPEATABLE-READ',8.0+ 废弃了 tx_isolation,只认 transaction_isolation。
常见错误现象:
- 在 8.0+ 执行
SET SESSION tx_isolation = 'READ-COMMITTED'→ 报错:Unknown system variable 'tx_isolation' - 误用引号类型,比如写成
SET SESSION transaction_isolation = "READ COMMITTED"(双引号 + 中间空格)→ 实际会被 MySQL 当作字符串字面量处理,不报错但不生效 - 在连接池场景下设了
SESSION级别,但连接复用后状态未重置,导致后续请求行为不一致
正确写法(8.0+):SET SESSION transaction_isolation = 'READ-COMMITTED';(单引号、全大写、无空格)
隔离级别不是越严越好:REPEATABLE-READ 是默认值,但可能引发幻读和间隙锁争用
MySQL 默认 REPEATABLE-READ 在可重复读基础上加了间隙锁(gap lock),能防幻读,但也带来副作用:高并发下容易锁等待甚至死锁,尤其在范围 UPDATE 或 DELETE 时。
使用场景判断:
- 业务能接受“同一事务中两次
SELECT返回不同行数”(即幻读),且主要做点查、更新单行 → 改READ-COMMITTED更轻量 - 有强一致性要求(如金融记账),且 SQL 已通过主键/唯一索引精准定位 →
READ-COMMITTED也够用,还能避免间隙锁 - 用到了
SELECT ... FOR UPDATE且涉及范围条件 → 要小心READ-COMMITTED下只锁记录不锁间隙,可能引发并发插入干扰
改配置前先确认实际生效的是哪个 my.cnf 文件
MySQL 启动时按固定顺序读多个配置文件,mysqld --help --verbose | grep "Default options" 显示的路径才是真实加载顺序。常见坑:
- 改了
/etc/my.cnf,但 MySQL 实际加载的是/usr/etc/my.cnf或~/.my.cnf(后者优先级更高,但只对客户端有效) - Docker 部署时挂载的配置文件路径没映射对,容器内
/etc/my.cnf根本没被覆盖 - 云数据库(如阿里云 RDS、AWS RDS)根本不允许改底层
my.cnf,只能通过控制台参数组调整,且部分参数不可修改
验证方法:SELECT @@global.config_file;(8.0.22+)或更通用的 SHOW VARIABLES LIKE 'config_file';,但注意该变量只在配置文件存在时才显示路径。
my.cnf 忘了重启,或者重启了但连错了端口、实例,查半天发现根本没生效。


















