两件库存的商品在十分钟里卖出五单,订单表全部成功,商品表 stock 字段变成 -3。后台库存显示「缺货」,前台却还能继续下单。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,扣库存的 UPDATE 写在下单事务提交之后,事务只包住了订单写入,两个请求同时读到 stock=2 都判断够卖。判断和扣减之间没有任何锁,读到的值早被别人改过。
「库存扣减超卖」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
UPDATE wp_sku SET stock = stock - 2 WHERE id = 9 AND stock >= 2; -- affected_rows = 0 表示库存不足,回滚事务 SHOW WARNINGS;
具体做法是,把判断和扣减合成一条 SQL,写成 UPDATE 带 stock >= 数量 的条件,用受影响行数判断成功与否;受影响行数为 0 就直接回滚并返回库存不足,不要再查一次库存做二次判断;给 stock 字段加无符号约束,扣成负数时数据库直接报错,能兜住漏改的分支。
最后用这个标准收尾,两个终端同时跑同样的下单脚本,只有一个成功,stock 停在 0 而不是负数。
