下单扣了库存,创建订单时唯一键冲突,回滚把库存加了回去。三分钟后超时释放任务又加了一次,goods_id 7710 的库存比实际多出 2 件。乍看像缓存或者权限的锅,追下去往往不是。
UPDATE stock_reserve SET status = 'RELEASED' WHERE id = 90211 AND status = 'HELD'; SELECT goods_id, sum(qty) FROM stock_reserve WHERE status = 'HELD' GROUP BY goods_id;
追下去是这么回事:扣库存和创建订单不在同一个事务,扣减时写了一条预占记录。订单创建失败后手工补偿了一次,预占记录没标成已释放,超时任务照着预占又释放一遍。
「库存反向补偿」这类改动最怕改一半,回滚脚本先准备好,再动生产。一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。
先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
具体做法是,预占记录加状态字段 只允许从 HELD 转到 RELEASED 一次;释放的 update 带 status=HELD 条件 影响行数为 0 就跳过;扣减和预占放进同一个本地事务;全量核对一次 多出的库存按预占记录反查修正。
验收就看一点,同一条预占记录只被释放一次 库存表数量和预占记录汇总能对上。
