MySQL线上核心服务常改用READ COMMITTED,因其语句级快照降低内存开销、仅加Record Lock减少死锁、且要求ROW格式binlog保障主从一致性,但需同步检查autocommit、锁行为及ORM事务配置。

MySQL默认用REPEATABLE READ,但线上核心服务(尤其是高并发写多读少场景)往往改成READ COMMITTED——这不是配置偏好问题,而是锁行为、快照生成逻辑和主从一致性这三块硬约束共同决定的。
RC每次SELECT都重生成快照,RR只在第一次SELECT时建快照
这意味着:在同一个事务里,READ COMMITTED下两次SELECT可能看到不同结果(因为其他事务已提交),而REPEATABLE READ下只要没改过本事务的数据,后续SELECT永远返回第一次查到的版本。
- 如果你的业务依赖“事务内多次读取必须一致”,比如订单创建时先查库存、再校验优惠、最后扣减,那
RR更安全 - 但如果你做的是状态轮询、实时监控类查询,或上层应用自己做了重试/幂等,
RC反而更贴近真实数据,避免“明明别人已提交,我却看不到”的困惑 -
RC的快照是语句级的,不维护长事务的全局一致性视图,内存开销更低;RR要一直保留事务启动时的快照,长时间运行的事务可能拖慢MVCC清理,加剧undo log膨胀
RC只加Record Lock,RR默认加Next-Key Lock(含Gap Lock)
InnoDB在RR下为防幻读,会对索引范围加Next-Key Lock(记录锁 + 间隙锁),哪怕WHERE条件没命中索引,也可能锁全表;而RC只对命中的行加Record Lock,不锁间隙。
- 这是大厂切
RC最直接动因:死锁概率大幅下降,尤其在UPDATE ... WHERE status = ?这类非唯一索引更新场景 - 如果
WHERE列没索引,RR会升级为表锁,RC仍只锁实际扫描到的行(虽然性能差,但至少不阻塞其他无关行) - 注意:
RC不是完全没幻读风险,只是InnoDB不靠锁解决,而是靠“每次读最新提交版本”来规避——所以它允许幻读,但业务上常感知不到
RC强制要求binlog格式为ROW,RR兼容STATEMENT/MIXED
MySQL主从复制中,READ COMMITTED隔离级别下binlog_format必须是ROW,否则会报错或自动降级;而REPEATABLE READ可自由选STATEMENT、ROW或MIXED。
- 用
STATEMENT格式时,某些函数(如NOW()、UUID())在主从上执行结果可能不一致,ROW则无此问题 - 阿里、拼多多等公司统一用
ROW+RC,既规避了STATEMENT的不确定性,又借RC释放了锁粒度 - 如果你还在用
STATEMENTbinlog(例如老系统迁移成本高),就不能轻易切RC,否则复制会中断
真正卡住决策的点往往不在理论对比表里:比如你改了隔离级别,但没同步检查autocommit是否关闭、SELECT ... FOR UPDATE语句是否还按旧逻辑加锁、或者ORM框架(如MyBatis)是否隐式开启了事务——这些细节比选RC还是RR更容易引发线上故障。


















