linlinjava/litemall · error · RuntimeException

商品货品库存增加失败

Error message

商品货品库存增加失败

What it means

In WxOrderService.cancel, after the order is successfully flipped to STATUS_CANCEL, the service restores inventory by calling productService.addStock(productId, number) for each order-goods row. addStock maps to a conditional SQL UPDATE (litemall_goods_product SET number = number + ?); 0 affected rows means the product row was not matched — typically the SKU was logically deleted or its id no longer resolves — and the service throws '商品货品库存增加失败' (stock restore failed). Because this runs after the status update within the same flow, the surrounding transaction must roll everything back, leaving the order un-cancelled.

Source

Thrown at litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/service/WxOrderService.java:587

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isCancel()) {
            return ResponseUtil.fail(ORDER_INVALID_OPERATION, "订单不能取消");
        }

        // 设置订单已取消状态
        order.setOrderStatus(OrderUtil.STATUS_CANCEL);
        order.setEndTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (LitemallOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Short number = orderGoods.getNumber();
            if (productService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        // 返还优惠券
        releaseCoupon(orderId);

        return ResponseUtil.ok();
    }

    /**
     * 付款订单的预支付会话标识
     * <p>
     * 1. 检测当前订单是否能够付款
     * 2. 微信商户平台返回支付订单ID
     * 3. 设置订单付款状态
     *
     * @param userId 用户ID
     * @param body   订单信息,{ orderId:xxx }

View on GitHub (pinned to a1ef964a71)

Solutions

  1. Check whether the 0-row result is due to logical delete of the SKU: if the row is gone for good, decide business-wise whether to skip restoring stock for that line (log it) instead of failing the whole cancel.
  2. If the cancel must succeed, wrap addStock per-item, log failures with productId, and continue — stock drift on a dead SKU is usually acceptable; order state consistency is not.
  3. Investigate the data: SELECT deleted, number FROM litemall_goods_product WHERE id=<productId> for each order_goods row of the failing order; fix orphaned references or re-create the SKU row.

Example fix

// before
if (productService.addStock(productId, number) == 0) {
    throw new RuntimeException("商品货品库存增加失败");
}

// after - log and continue so cancellation is not blocked by a dead SKU
if (productService.addStock(productId, number) == 0) {
    logger.error("库存返还失败, 货品不存在或已删除, productId={}, orderId={}", productId, orderId);
}
Defensive patterns

Strategy: fallback

Validate before calling

// optional pre-check: identify dead SKUs before cancelling
List<LitemallOrderGoods> goods = orderGoodsService.queryByOid(orderId);
for (LitemallOrderGoods og : goods) {
    if (productService.findById(og.getProductId()) == null) {
        logger.warn("订单{}包含已删除货品{},取消时将跳过库存返还", orderId, og.getProductId());
    }
}

Try / catch

for (LitemallOrderGoods orderGoods : orderGoodsList) {
    if (productService.addStock(orderGoods.getProductId(), orderGoods.getNumber()) == 0) {
        // dead SKU: log and continue — do not block the cancellation
        logger.error("库存返还失败 productId={} orderId={}", orderGoods.getProductId(), orderId);
    }
}

Prevention

When it happens

Trigger: An order contains a product SKU that has since been logically deleted (deleted=1) or hard-removed by an admin; the order_goods row references a productId that no longer exists in litemall_goods_product (data drift from manual edits/imports). The cancel itself succeeds but the very first addStock UPDATE matches 0 rows.

Common situations: Admin deletes obsolete SKUs while old unshipped orders for them still exist; store data migrated/pruned without preserving product ids; test databases with order_goods rows referencing seeded products that were wiped.

Related errors


AI-assisted analysis of linlinjava/litemall@a1ef964a71 (2026-08-14). Data as JSON: /api/errors/a7d6b165a3fd2274. Report an issue: GitHub.