mysql乐观锁在写多读少场景下根本无法收敛——重试导致雪崩式sql请求、undo log开销累积、索引缺失引发全表扫描,失败率趋近100%,有效吞吐接近于零。

MySQL乐观锁在写多读少场景下不是“效果变差”,而是根本无法收敛——重试逻辑会瞬间把系统拖垮,失败率趋近100%。
UPDATE WHERE version = ? 影响行为为 0 是常态,不是异常
写多读少意味着多个事务几乎同时读取同一行(比如高频更新的计数器、状态机字段),它们拿到的 version 值完全一致。随后并发执行:
UPDATE t SET status = 'done', version = version + 1 WHERE id = 123 AND version = 5
只有第一个事务能成功(影响 1 行),其余全部返回 0 行影响。这不是偶发错误,是必然结果。
若业务代码按默认逻辑立即重试(比如 retryTimes-- 后立刻再查再更新),就会触发雪崩式 SQL 请求:100 个并发请求可能生成 300+ 次无意义的 SELECT 和 UPDATE,而真正成功的可能只有 1–2 个。
version 字段本身在高写入下成为性能瓶颈
每次成功更新都要递增 version,这看似简单,但在高频写场景下带来两个隐性开销:
-
version字段使每行数据变大,降低 Buffer Pool 缓存效率,间接增加磁盘 IO - 每次
UPDATE失败时,MySQL 仍会生成 undo log 并尝试写入,只是最终回滚——这部分开销常被忽略,但高冲突下累计可观
更关键的是:如果表没有为 WHERE id = ? AND version = ? 建联合索引,UPDATE 可能走全表扫描或主键回表,IO 和 CPU 成倍升高。
重试策略不退让,等于把竞争从数据库层推给应用层
乐观锁的重试不是“等一会儿再试”,而是无延迟、无退避地发起新查询。这导致:
- 应用线程池被阻塞在空转循环里,无法释放,容易引发下游超时雪崩
- 数据库压力不降反升:连接数、CPU、IO 全面拉满,而有效吞吐接近于零
- 若业务要求“失败即告终”(如支付状态变更),那 90% 的请求直接变成业务错误,不可接受
真正卡住人的,从来不是锁类型本身,而是没意识到:乐观锁的有效性极度依赖冲突率。一旦真实冲突超过 15%,它的吞吐量往往不如一个锁粒度精准、事务边界清晰的悲观锁方案。











