mysql默认隔离级别是repeatable read,但高并发读多写少场景下,改用read committed可降低锁竞争、提升吞吐,需在事务开始前设置会话级级别或全局配置并重启。

MySQL 默认的 REPEATABLE-READ 隔离级别在大多数业务场景下已足够,但若遇到高并发读多写少、又对“不可重复读”容忍度较高(如商品库存查询、用户资料展示),改用 READ-COMMITTED 能显著降低锁竞争,提升吞吐量。
查看当前隔离级别必须分清 session 和 global
直接执行 SELECT @@transaction_isolation 看到的是当前会话值,它可能已被应用代码或连接池临时覆盖;而 SELECT @@global.transaction_isolation 才反映 MySQL 启动时加载的默认配置。旧版本(5.7 及之前)还可能返回 tx_isolation 变量名,所以建议两条都查:
SELECT @@session.transaction_isolation, @@global.transaction_isolation;
注意:如果返回 NULL 或空字符串,说明配置有语法错误或未生效,不是“没设置”,而是设置失败了。
修改会话级隔离级别必须在 START TRANSACTION 之前
这是最容易踩的坑——一旦事务已开启,再执行 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED 会立刻报错:Can’t change transaction isolation level when a transaction is active。常见于 ORM 框架(如 Spring 的 @Transactional)自动开启事务后,再试图动态切级别。
可行做法包括:
- 在连接初始化阶段(如连接池
initSql配置项)执行SET SESSION TRANSACTION ISOLATION LEVEL ... - 在业务逻辑入口处、显式调用
START TRANSACTION前设置 - 避免在事务中嵌套修改,尤其是使用连接复用的长连接场景
全局修改需重启且只影响新会话
执行 SET GLOBAL transaction_isolation = 'READ-COMMITTED' 后,已有连接仍保持原会话级别,只有后续新建连接才会继承该值。但该命令不会持久化到配置文件,MySQL 重启即失效。
要永久生效,必须编辑 my.cnf(Linux)或 my.ini(Windows),在 [mysqld] 段落下添加:
transaction-isolation = READ-COMMITTED
注意:transaction-isolation 中的连字符不能写成下划线,大小写不敏感但空格和引号会导致启动失败;修改后必须重启 MySQL 进程,SIGHUP 或 FLUSH PRIVILEGES 无效。
REPEATABLE-READ 下的幻读其实比想象中难触发
很多人因文档里写着“REPEATABLE-READ 不能完全避免幻读”就换级别,但 InnoDB 实际通过 Next-Key Lock(行锁 + 间隙锁)在绝大多数 WHERE 查询路径上拦截了新增记录。真正容易漏掉幻读的场景是:
- 非唯一索引 + 范围查询(如
WHERE status IN (1,2))且无对应索引覆盖 - 使用
SELECT ... FOR UPDATE但条件未命中任何现有行,导致间隙锁范围过大或失效 - INSERT SELECT 场景下,源表读取用的是快照,目标表插入却是当前最新状态
这类问题靠改隔离级别解决不了,得靠索引优化、显式加锁或业务层重试控制。











