SHOW ENGINE INNODB STATUS\G
SELECT id FROM orders WHERE id IN (11, 12)
ORDER BY id FOR UPDATE;

每天凌晨的结转任务都报 1213,死锁日志里 LATEST DETECTED DEADLOCK 一段显示两个事务各持一个主键的锁,等的正是对方手里那条。回滚的总是同一个任务。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,两个事务更新同一批订单,一个按 id 升序、另一个按用户分组后的顺序,加锁顺序相反就形成环。InnoDB 检测到环后挑代价小的一方回滚,业务看到的是随机失败。

这次卡住的地方就在「加锁顺序」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

处理上按这个顺序:把两个事务里 update 的 id 列表都按升序排一遍再执行;一次锁定多行时先用 for update 按固定顺序拿锁;捕获 1213 后整事务重试 不要只重试报错那条语句;死锁日志留档 每周看一次是不是同一对 SQL。

改完只确认一件事:连续跑三天结转任务 1213 不再出现 死锁日志里也没有新的环。

作者 9823189