mysql事务隔离级别控制一个事务能看到其他并发事务提交到哪一步的数据,本质是性能与一致性权衡;默认rr级仅配合间隙锁时防幻读,rc级间隙锁失效即出现幻读。

MySQL事务隔离级别到底控制什么
它控制的是:**一个事务能看到其他并发事务做到哪一步的数据**。不是“能不能读”,而是“读到的是哪个时间点、谁提交过的数据”。本质是数据库在性能和一致性之间做的权衡。
MySQL默认用 REPEATABLE READ,但很多人误以为它能完全避免幻读——其实只在配合间隙锁(Gap Lock)时才成立;一旦用了 READ COMMITTED,间隙锁就失效,幻读立刻出现。
四种隔离级别对应的真实行为差异
别死记“脏读/不可重复读/幻读”定义,看实际表现更准:
-
READ UNCOMMITTED:SELECT 不加任何版本过滤,直接读最新行数据(哪怕在别的事务里还没 COMMIT),SELECT可能返回回滚前的中间态 -
READ COMMITTED:每次SELECT都生成新 Read View,所以同一事务内两次查同一条记录,可能得到不同结果(比如另一事务刚 UPDATE+COMMIT) -
REPEATABLE READ:整个事务只建一次 Read View,保证“可重复读”;但对WHERE id BETWEEN 10 AND 20 FOR UPDATE这类范围查询,InnoDB 会自动加间隙锁,堵住插入,防幻读 -
SERIALIZABLE:所有普通SELECT都隐式转成SELECT ... LOCK IN SHARE MODE,写操作冲突时直接等锁,几乎无并发
怎么查和改当前隔离级别
别信配置文件里写的,运行时可能被连接层覆盖。必须查当前会话真实值:
SELECT @@transaction_isolation;
修改只对当前会话生效,重启即丢:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
注意:SET GLOBAL 改全局会影响后续新连接,但**不会改变已有连接的级别**;线上调参前务必确认连接池是否复用长连接。
最容易被忽略的坑:RR 级别下幻读没消失?
很多人测试发现 REPEATABLE READ 下还是有幻读——十有八九是因为用了非唯一索引或没走索引:
- 只有在**索引列上做等值或范围查询 + FOR UPDATE / LOCK IN SHARE MODE** 时,InnoDB 才会启用临键锁(Next-Key Lock)
- 如果
WHERE条件没命中索引,会退化为表锁;如果条件命中的是二级索引且没包含主键,间隙锁范围可能比预期大得多 - 用
SELECT ... FOR UPDATE时若未匹配到记录,InnoDB 仍会在扫描区间加间隙锁——这点常被当成“莫名卡住”的原因
真正稳住幻读的组合是:REPEATABLE READ + 唯一/主键等值条件 + 显式加锁。其它情况,别轻信“MySQL 已解决幻读”。










