MySQL默认且最常用READ COMMITTED,因其在避免脏读前提下兼顾并发性能与开发直觉;普通SELECT为快照读不加锁,UPDATE/DELETE仅锁匹配行、不锁间隙。
READ COMMITTED 为什么是 MySQL 默认且最常用的选择
MySQL InnoDB 默认隔离级别是 READ COMMITTED,不是因为“最安全”,而是它在避免脏读的前提下,兼顾了并发性能与开发直觉。多数业务场景(如订单创建、库存扣减、用户资料更新)不需要可重复读语义,却极度敏感于锁等待和死锁。
-
READ COMMITTED下,普通SELECT是快照读(不加锁),而UPDATE/DELETE只锁匹配到的行(基于聚簇索引),不会锁间隙 - 同一事务内多次执行相同
SELECT,可能看到其他事务已提交的新数据 —— 这是预期行为,不是 bug - 如果你在应用层做了“先查后更”的逻辑(比如查余额 → 判断是否足够 → 扣款),
READ COMMITTED下仍可能因并发导致超扣,必须靠SELECT ... FOR UPDATE显式加锁
REPEATABLE READ 真正锁住的是什么,而不是“数据不变”
很多人误以为 REPEATABLE READ 能保证事务中所有 SELECT 结果一致,其实它只保证“同一查询在事务内返回相同快照”,但这个快照的生成时机是第一次 SELECT 执行时,且它的锁机制比表面更重。
-
UPDATE t SET x=1 WHERE id = 5在REPEATABLE READ下不仅锁住id=5的行,还会锁住前后间隙(Next-Key Lock),防止幻读 - 这意味着一个看似简单的等值更新,可能意外阻塞其他事务对相邻 ID 的插入或更新
- 如果表没有显式主键或唯一索引,InnoDB 会用隐式聚簇索引,此时
REPEATABLE READ的间隙锁范围更难预测,容易引发莫名锁等待
Serializable 会让事务退化成串行执行,但未必解决你想象的问题
SERIALIZABLE 是 SQL 标准定义的最高隔离级别,在 MySQL 中它会让所有普通 SELECT 隐式转为 SELECT ... LOCK IN SHARE MODE,相当于给扫描到的每一行都加共享锁。