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
- Reset the product stock in the DB (re-run the lab's SQL init script or `UPDATE product SET stock = 1000 WHERE id = ?`).
- Retry the order with a smaller amount.
- 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
- Restock demo products before test runs.
- Keep amount ≤ single-item quantity sanity-checked at the controller.
- Rely on the guarded UPDATE, not the pre-check, for correctness under concurrency.
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.