订单状态更新和用户查询并发发生时,你们怎么选择隔离级别?MVCC 在里面起什么作用?
我的判断
订单查询通常用 MVCC 做非阻塞快照读,状态更新用条件更新或显式锁保证并发正确;隔离级别按业务一致性选择。
大多数订单系统我会从 READ COMMITTED 或 REPEATABLE READ 中选。列表查询接受同一事务内再次查询看到新提交数据时,RC 更直观;对账或一次事务内需要稳定快照时用 RR。选择不是背默认值,而是把“同一请求能否看到别人刚提交的状态”写清楚。
MVCC 让普通 SELECT 通过 Read View 和版本链读取快照,不和更新行直接互斥,但它不会自动防止两个请求同时把 PAID 改成不同状态。更新会写成带前置状态或版本的条件语句:
UPDATE orders
SET status = ?, version = version + 1
WHERE id = ? AND status = ? AND version = ?;
受影响行为 0 就说明状态已变化,业务决定返回幂等成功、冲突还是重试。确实需要“读后立刻改且中间不能变”时才用 SELECT ... FOR UPDATE,并把事务保持很短。
还会关注长事务:它会让旧版本无法清理,Undo 增长并拖慢查询。隔离级别不能替代正确的状态机和幂等。
容易答偏踩坑误区
- 认为 MVCC 能解决丢更新。 快照读不等于写入冲突检测。
- 所有查询都加 FOR UPDATE。 会把本可并发的订单查询串行化。
- 事务里调用远程服务。 锁和旧版本会被无谓地长时间保留。