RC下“读-判-写”易出错,因每次SELECT生成新ReadView,可立即看到其他事务已提交变更,而RR中事务内ReadView固定;典型问题如余额判断后扣款、状态检查后发消息均可能因未重查导致超扣或重复操作。

RC 下“读-判-写”逻辑容易出错,不是隔离级别本身有问题,而是应用没适配新语义。
为什么 RC 切换后突然出现写覆盖或判断失效?
RR 下事务内第一次 SELECT 就固定了 ReadView,后续所有读都看到同一快照;RC 下每次 SELECT 都生成新 ReadView,能立刻看到别人刚 COMMIT 的变更。典型崩坏场景:
- “查余额 → 判断 ≥100 → 扣款”:在 RC 下,第二次读(判断前)可能看到别人刚扣走的钱,但你的判断逻辑仍按旧值走,导致超扣
- “查状态 = 'pending' → 发送消息 → 改状态为 'sent'”:并发时两个事务都查到 pending,都发消息,再各自改状态
- 应用层用本地缓存或变量保存了第一次查询结果,却没重新查库就直接写入
哪些 SQL 模式在 RC 下必须重审?
不是所有语句都会出问题,但以下几类必须人工过一遍逻辑:
- 带条件的
UPDATE或DELETE,且 WHERE 条件依赖之前SELECT结果(比如UPDATE t SET status='done' WHERE id IN (SELECT id FROM t WHERE status='pending')) - 业务代码里显式用了
SELECT ... FOR UPDATE,但没加WHERE索引字段——RC 虽不加间隙锁,但全表扫描仍会锁所有命中行,性能反而更差 - 用
INSERT ... ON DUPLICATE KEY UPDATE做幂等写入,但判断依据是非唯一字段(如 status),RC 下并发插入可能绕过唯一约束触发多次更新 - 存储过程中嵌套多条
SELECT+UPDATE,且中间没加锁或重查
怎么验证“读-判-写”链路是否安全?
不能只看单次执行是否报错,重点是模拟并发下行为是否符合预期:
- 压测时用至少 2 个线程同时跑同一笔订单的“查+判+改”,观察最终状态和业务指标(如扣款总金额)是否唯一、正确
- 在测试库开慢日志,过滤
Lock_wait和Rows_affected异常波动,RC 下锁等待应减少,但如果SELECT FOR UPDATE没走索引,反而可能锁更多行 - 检查 binlog 格式是不是
ROW:RC 下若还用STATEMENT,主从延迟和数据不一致风险比 RR 更高 - 把关键路径的日志加上前后
SELECT结果对比,确认判断依据是否被其他事务中途修改
切换 RC 最容易被忽略的点:不是配置改了就完事,而是所有依赖“事务内读一致性”的业务逻辑都要重走一遍并发路径。哪怕只有一处 if (balance > 0) { update ... } 没重查,就可能在线上引发资损。


















