两个事务都先 select ... lock in share mode 读同一行做校验,再 update 该行,结果两边都卡住,10 秒后其中一个报 1213。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,共享锁可以多个事务同时持有,升级成排他锁时要等对方先释放。两个事务都拿着共享锁等对方放手,谁也不肯先退。这种模式在读完再改的流程里很常见。
「共享锁升级」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。改完顺手把文档补一句,省得下次自己重新推一遍。
SELECT * FROM stock WHERE id = 1 FOR UPDATE; SHOW ENGINE INNODB STATUS\G
监控和日志的时间要对上,时区不一致会多绕很大一圈。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。
具体做法是,把共享锁读改成 for update 一次拿到排他锁;缩短读和写之间的间隔 别在中间做远程调用;业务允许就改成普通读 用乐观锁在写时校验;固定先读后写的顺序 避免两边交叉。
最后用这个标准收尾,并发校验加扣减不再出现互等 1213 消失 扣减结果与库存一致。
