READ COMMITTED 是大多数业务的合理起点,它关闭间隙锁、减少死锁、提升吞吐,适用于订单状态流转等场景,但需接受同一事务内两次 SELECT 结果可能不同。

READ COMMITTED 是大多数业务的合理起点
MySQL 默认隔离级别是 REPEATABLE READ,但它在高并发更新场景下容易因间隙锁(gap lock)引发死锁或锁等待,尤其在范围查询 + UPDATE/DELETE 混合时。而 READ COMMITTED 关闭间隙锁(InnoDB 下配合 innodb_locks_unsafe_for_binlog=OFF 已默认生效),锁粒度更细、冲突更少,吞吐更高。
适用场景包括:电商订单状态流转、用户积分增减、日志类写多读少服务。只要业务能接受“同一事务内两次 SELECT 可能拿到不同结果”(即不依赖可重复读语义),READ COMMITTED 就比默认更稳。
- 确认当前会话级别:执行
SELECT @@tx_isolation; - 临时切换:运行
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; - 全局修改需重启或动态设置(MySQL 5.7+ 支持
SET GLOBAL tx_isolation = 'READ-COMMITTED';),但注意 binlog 格式必须为ROW才安全
REPEATABLE READ 真正需要它的场景其实不多
很多人以为“防止幻读”必须用 REPEATABLE READ,但 MySQL 的 REPEATABLE READ 实际通过 MVCC + 间隙锁模拟可重复读,代价是锁范围扩大。真正需要它的情况只有两类:
- 报表类任务:一个长事务内多次统计同一张表的 COUNT/SUM,且要求结果严格一致(如财务对账)
- 依赖 SELECT ... FOR UPDATE + 后续 INSERT 的业务逻辑(例如“查无记录则插入”,且不允许并发插入)——但这本身设计有缺陷,应改用唯一索引 + INSERT IGNORE / ON DUPLICATE KEY UPDATE
注意:REPEATABLE READ 下 SELECT 不加锁,但 UPDATE 和 DELETE 仍可能锁住整个范围,比如 WHERE status IN (1,2) 可能锁住所有 status=0~3 的记录。
READ UNCOMMITTED 和 SERIALIZABLE 基本该被排除
READ UNCOMMITTED 允许脏读,在 MySQL 中极少使用。即使日志分析类场景,也建议用 READ COMMITTED + 快照读,而非容忍未提交数据污染结果。
SERIALIZABLE 本质是把所有普通 SELECT 都转成 SELECT ... LOCK IN SHARE MODE,性能断崖式下跌,QPS 常掉 50% 以上。除非满足两个条件才考虑:① 数据绝对不可错(如银行核心账务核验);② 并发量极低(TPS
常见误操作:SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; 后忘记改回来,导致后续接口莫名变慢,排查时容易忽略隔离级别这个维度。
验证锁行为比背概念更重要
别只记“RR 防幻读、RC 不防”,直接看锁——用 SELECT * FROM performance_schema.data_locks;(MySQL 8.0+)或 SHOW ENGINE INNODB STATUS\G 观察实际加锁范围。例如执行 UPDATE t SET x=1 WHERE id > 100; 后:
- 在
REPEATABLE READ下可能锁住 id=101 到下一个索引值之间的所有间隙 - 在
READ COMMITTED下只锁住实际命中的行(前提是有有效索引)
真实压测中,把隔离级别从 RR 改为 RC 后 QPS 提升 2–3 倍并不罕见,但前提是业务没隐式依赖“两次读一致”。上线前务必用影子流量或预发布环境跑通核心链路,重点看资金、库存、计数类逻辑是否出现预期外的不一致。


















