MySQL默认隔离级别是REPEATABLE READ,但并非所有场景都适用;电商金融等强一致性业务适合RR,而高并发查询服务常降级到READ COMMITTED以提升性能、降低死锁。

MySQL默认用的是可重复读,但你真需要它吗?
MySQL默认事务隔离级别是 REPEATABLE READ,不是大多数OLTP系统更常用的 READ COMMITTED。这容易让人误以为“默认=推荐”,但实际取决于场景:电商库存扣减、金融对账这类强一致性要求的业务适合RR;而高并发查询密集型服务(如商品详情页、用户中心)往往主动降级到RC来减少锁竞争和死锁概率。
- RR下InnoDB用Next-Key Lock(间隙锁+记录锁)防幻读,但会锁住范围,导致插入阻塞——比如
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE可能锁住整个status索引段 - RC只在读取时做快照,不加间隙锁,写操作仅锁被修改的行,响应更快,主从复制延迟更低(尤其配合
binlog_format = ROW) - 别盲目改全局级别:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED会影响所有新连接,但已有连接不受影响,且某些中间件(如ShardingSphere)可能覆盖该设置
怎么查和改当前会话的隔离级别?
最常踩的坑是查错对象:很多人用 SELECT @@tx_isolation,但MySQL 8.0+已弃用该变量,正确方式是 SELECT @@transaction_isolation。改级别也分作用域,一不留神就只改了当前SQL会话,没生效到业务连接池里。
- 查当前会话:
SELECT @@transaction_isolation;
- 设当前会话(重启连接即失效):
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
- 设全局(需SUPER权限,且新连接才生效):
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
- Spring Boot应用中,若用
@Transactional(isolation = Isolation.READ_COMMITTED),实际生效还取决于连接池是否允许覆盖——HikariCP默认允许,Druid需配allowMultiQueries=true
脏读、不可重复读、幻读,到底哪个在哪个级别消失?
标准SQL定义和MySQL实际行为有差异。比如“幻读在RR级别被解决”是常见误解——MySQL的RR确实通过MVCC+间隙锁大幅抑制幻读,但**仅限于快照读(普通SELECT)**;一旦用了SELECT ... FOR UPDATE或UPDATE ... WHERE这种当前读,就可能因锁范围变化暴露幻行。
-
READ UNCOMMITTED:脏读、不可重复读、幻读全存在 -
READ COMMITTED:脏读消失,不可重复读和幻读仍存在(两次SELECT可能看到不同行数) -
REPEATABLE READ:脏读、不可重复读消失;幻读在快照读中被MVCC屏蔽,但在当前读中可能重现(尤其范围条件+并发INSERT) -
SERIALIZABLE:全部消失,但所有SELECT自动转为SELECT ... LOCK IN SHARE MODE,并发能力断崖式下降
为什么大厂线上库常把RR改成RC?
不是为了“更先进”,而是权衡结果:500并发下RC平均响应时间比RR快40%,死锁率降低75%。典型案例如双11订单创建,大量INSERT INTO order (user_id, amount) VALUES (?, ?)并发执行,RR的间隙锁会让相邻ID插入互相等待,而RC只锁具体行,吞吐翻倍。
- 风险可控:幻读对多数业务无实质影响——用户注册用唯一索引防重,库存扣减用
UPDATE ... SET stock = stock - 1 WHERE id = ? AND stock > 0做CAS校验 - 主从复制更稳:RC下binlog写入的是语句执行时的真实数据版本,避免RR因长事务导致主从间同一SQL看到不同快照
- 注意例外:银行核心账务系统仍坚持RR,因其日终批量必须保证“两次SELECT COUNT(*)结果绝对一致”,哪怕牺牲性能
MySQL的隔离级别不是配置开关,而是数据一致性与并发吞吐之间的连续光谱。真正关键的不是选哪个级别,而是清楚知道:你正在容忍什么问题,又用什么手段兜底。










