mysql根本不支持快照隔离,因此不处理写偏斜;其repeatable read依赖mvcc+临键锁,read view在首次快照读时生成而非事务开始时,既无全局一致快照起点,也无提交时写冲突验证机制,导致写偏斜必然发生且无法拦截。

MySQL根本不支持快照隔离,所以不处理写偏斜
MySQL 的 REPEATABLE READ 不是快照隔离(SI),它既不提供 SI 语义,也不做写偏斜检测。你执行 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ,得到的仍是 InnoDB 原生的 RR —— 依赖 MVCC + 临键锁实现,Read View 在第一次快照读时生成,而非事务 START 时刻。这意味着:没有全局一致快照起点,也没有提交时的写冲突验证机制。
写偏斜在 MySQL RR 下必然发生,且无法被拦截
典型场景:账户余额约束 x + y = 100,初始 x=50, y=50。事务 A 读 x=50,事务 B 读 y=50;A 把 x 改为 60,B 把 y 改为 60;两者都成功提交。最终 x+y=120,约束被破坏。这种 r1[x] w2[y] w1[x] r2[y] 类型的写偏斜,在 MySQL RR 下:
- 不会报错,也不会阻塞
-
SELECT是快照读,彼此不可见对方未提交的写 -
UPDATE只锁住自己修改的行(通过临键锁),不检查逻辑相关字段是否被并发修改 - 没有类似 PostgreSQL 的
SELECT ... FOR KEY SHARE或 SQL Server 的 SI 提交时验证环节
想规避写偏斜?只能靠应用层或锁机制补救
MySQL 没有内置的写偏斜防护,但你可以用以下方式降低风险:
- 用
SELECT ... FOR UPDATE显式锁定所有相关行(比如同时查 x 和 y 并加锁),把并发写变成串行化执行 - 在应用层加分布式锁或业务状态校验(例如提交前再查一遍 x+y 是否仍为 100)
- 改用
SERIALIZABLE隔离级别——它会自动将普通SELECT转为加锁读,但代价是显著降低并发度 - 避免在事务中分步读-改-写多个弱关联字段;尽量合并为单条带条件的
UPDATE,如UPDATE t SET x = x + 10 WHERE x + y = 100
TiDB 和 PostgreSQL 的对比提醒
如果你真需要 SI 语义和写偏斜检测,别指望 MySQL:
- TiDB(v3.0+)默认的
REPEATABLE READ实际是快照隔离,提交时会做 write skew 检查,冲突则报ERROR 8005 (HY000): Transaction is rolled back due to data conflict - PostgreSQL 的
REPEATABLE READ行为接近 SI,但需配合SELECT ... FOR KEY SHARE才能触发写偏斜检测;纯快照读仍可能出问题 - SQL Server 的
SNAPSHOT隔离级不检测写偏斜,而READ COMMITTED SNAPSHOT也不检测——只有启用ALLOW_SNAPSHOT_ISOLATION后显式设为SNAPSHOT,并依赖应用层逻辑或触发器兜底
写偏斜不是“偶尔出现的 bug”,它是快照类隔离的固有行为边界。MySQL 从没承诺解决它,指望配置调参绕过去,只会让问题更隐蔽。











