REPEATABLE READ 并未真正消除幻读,而是通过间隙锁阻止新记录插入;READ COMMITTED 每次 SELECT 都新建快照,导致不可重复读;binlog_format 非 ROW 时切换隔离级别易致主从不一致;显式加锁和 CAS 更新比依赖隔离级别更可靠。
很多人以为 REPEATABLE READ 能彻底避免幻读,但 MySQL InnoDB 的实现是通过间隙锁(Gap Lock)+ 行锁来“阻止”新记录插入,而不是真正消除幻读语义。这意味着:在同一个事务里两次执行

SELECT ... WHERE x > 10,第二次不会看到新插入的满足条件的行——但这只是锁机制压制了并发写入,并非快照隔离意义上的“无幻读”。
实际业务中容易踩的坑:
REPEATABLE READ 可能导致大量间隙锁冲突,出现 Lock wait timeout exceeded
SELECT ... FOR UPDATE 时,InnoDB 会锁住范围,哪怕 WHERE 条件命中的是空结果集,也会加间隙锁WHERE id > ? LIMIT 20)在 REPEATABLE READ 下可能因间隙锁阻塞写入,拖慢吞吐READ COMMITTED 在 InnoDB 中意味着:每个 SELECT 语句都会生成一个新的一致性读视图(consistent read view),不复用事务内之前的快照。这直接导致同一事务中两次读取可能看到不同数据——不是脏读,而是“不可重复读”真实发生。
典型影响场景:
READ COMMITTED 下第二步判断依据的余额可能已被其他事务改过SELECT 拼接数据,各表快照时间点不同,最终结果可能逻辑自洽但业务上失真(比如订单数和支付流水数对不上)SELECT,也各自开快照,行为更难预测MySQL 启用 binlog_format = ROW 时,REPEATABLE READ 和 READ COMMITTED 对主从复制的影响差异不大;但若设为 MIXED 或 STATEMENT,问题就来了:
READ COMMITTED 下的非确定性函数(如 NOW()、UUID())在 STATEMENT 模式下可能导致主从不一致READ COMMITTED 下不启用间隙锁,而某些 DML 语句(如 DELETE ... LIMIT)在 STATEMENT binlog 中可能被重放为不同结果binlog_format 是 ROW,否则复制延迟或数据错乱风险陡增依赖隔离级别“自动保护”很容易误判。比如认为 REPEATABLE READ 就能保证「查-改」原子性,实际上它只保证读结果不变,不保证后续更新不失败。
真正稳的做法是主动控制:
SELECT ... FOR UPDATE 显式加锁,且确保 WHERE 条件能命中索引(否则升级为表锁)UPDATE ... WHERE version = ? + CAS 逻辑,比依赖事务隔离更直观可控最常被忽略的一点:应用层连接池配置的 defaultTransactionIsolation 可能被框架覆盖,上线前必须用 SELECT @@tx_isolation 实际验证,不能只信配置文件。