yudaocode/SpringBoot-Labs · error · java.lang.Exception

库存不足

Error message

库存不足

What it means

Thrown by the product (stock) service in the Seata AT demo (lab-53). reduceStock issues a conditional UPDATE (typically `UPDATE product SET stock = stock - ? WHERE id = ? AND stock >= ?`); a return of 0 affected rows means the guard failed, and the service throws to signal insufficient stock. As a Seata branch exception it causes the global transaction (order + account + product) to roll back.

Source

Thrown at lab-53/lab-53-seata-at-dubbo-demo/lab-53-seata-at-dubbo-demo-product-service/src/main/java/cn/iocoder/springboot/lab53/productservice/service/ProductServiceImpl.java:33

    @Autowired
    private ProductDao productDao;

    @Override
    @Transactional // 开启新事物
    public void reduceStock(Long productId, Integer amount) throws Exception {
        logger.info("[reduceStock] 当前 XID: {}", RootContext.getXID());

        // 检查库存
        checkStock(productId, amount);

        logger.info("[reduceStock] 开始扣减 {} 库存", productId);
        // 扣减库存
        int updateCount = productDao.reduceStock(productId, amount);
        // 扣除成功
        if (updateCount == 0) {
            logger.warn("[reduceStock] 扣除 {} 库存失败", productId);
            throw new Exception("库存不足");
        }
        // 扣除失败
        logger.info("[reduceStock] 扣除 {} 库存成功", productId);
    }

    private void checkStock(Long productId, Integer requiredAmount) throws Exception {
        logger.info("[checkStock] 检查 {} 库存", productId);
        Integer stock = productDao.getStock(productId);
        if (stock < requiredAmount) {
            logger.warn("[checkStock] {} 库存不足,当前库存: {}", productId, stock);
            throw new Exception("库存不足");
        }
    }

}

View on GitHub (pinned to 6c12efaed0)

Solutions

  1. Reset the product stock in the DB (re-run the lab's SQL init script or `UPDATE product SET stock = 1000 WHERE id = ?`).
  2. Retry the order with a smaller amount.
  3. Keep the conditional UPDATE as the authoritative guard and map this exception to a user-facing 'out of stock' message at the order-service boundary.

Example fix

// before
int updateCount = productDao.reduceStock(productId, amount);
if (updateCount == 0) {
    throw new Exception("库存不足");
}

// after — domain exception; SQL guard remains the source of truth
int updateCount = productDao.reduceStock(productId, amount);
if (updateCount == 0) {
    throw new OutOfStockException(productId, amount);
}
Defensive patterns

Strategy: validation

Validate before calling

// Check stock before creating the order
Integer stock = productApi.getStock(productId);
if (stock == null || stock < amount) {
    return Result.error("库存不足,当前库存:" + stock);
}

Try / catch

try {
    orderService.create(userId, productId, amount);
} catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().contains("库存不足")) {
        return ResponseEntity.badRequest().body("out of stock");
    }
    throw e;
}

Prevention

When it happens

Trigger: Placing an order whose amount exceeds the product's remaining stock such that the conditional UPDATE matches 0 rows (e.g. stock exhausted between the pre-check and the update, or the pre-check itself was skipped/bypassed). Line 33 is the `throw new Exception("库存不足")` after `updateCount == 0`.

Common situations: Previous demo runs consumed the seeded stock without reseeding the product table; concurrent purchases of the last units race past the checkStock pre-check; the amount parameter is accidentally large (e.g. passing a price instead of a quantity).

Related errors


AI-assisted analysis of yudaocode/SpringBoot-Labs@6c12efaed0 (2026-08-14). Data as JSON: /api/errors/40082aff6c113d66. Report an issue: GitHub.