yudaocode/SpringBoot-Labs · error · java.lang.RuntimeException
扣除余额失败
Error message
扣除余额失败
What it means
Mirror of error 18: the order service calls the account service at http://127.0.0.1:8083/account/reduce-balance via Seata's DefaultHttpExecutor and throws RuntimeException('扣除余额失败') when the response body isn't true. The XID-propagating HTTP call makes the deduction a branch of the global transaction; the throw rolls the whole purchase back (order insert + stock deduction).
Source
Thrown at lab-52/lab-52-seata-at-httpclient-demo/lab-52-seata-at-httpclient-demo-order-service/src/main/java/cn/iocoder/springboot/lab52/orderservice/service/OrderServiceImpl.java:72
params, HttpResponse.class);
// 解析结果
Boolean success = Boolean.valueOf(EntityUtils.toString(response.getEntity()));
if (!success) {
throw new RuntimeException("扣除库存失败");
}
}
private void reduceBalance(Long userId, Integer price) throws IOException {
// 参数拼接
JSONObject params = new JSONObject().fluentPut("userId", String.valueOf(userId))
.fluentPut("price", String.valueOf(price));
// 执行调用
HttpResponse response = DefaultHttpExecutor.getInstance().executePost("http://127.0.0.1:8083", "/account/reduce-balance",
params, HttpResponse.class);
// 解析结果
Boolean success = Boolean.valueOf(EntityUtils.toString(response.getEntity()));
if (!success) {
throw new RuntimeException("扣除余额失败");
}
}
}
View on GitHub (pinned to 6c12efaed0)
Solutions
- Top up the test user's balance (or lower the order price) so reduce-balance succeeds.
- Ensure the account service (8083) and Seata server are running before creating orders.
- Confirm both /product and /account services join the same XID (check RootContext.getXID() logs on each service) so rollback spans them.
- Include the remote body/status in the thrown message to speed up diagnosis.
Example fix
// before
if (!success) {
throw new RuntimeException("扣除余额失败");
}
// after
if (!success) {
throw new RuntimeException("扣除余额失败: userId=" + userId + ", price=" + price);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm sufficient balance before creating the order:
Integer balance = accountClient.getBalance(userId);
if (balance == null || balance < price) {
throw new OrderRejectedException("INSUFFICIENT_BALANCE");
} Try / catch
try {
reduceBalance(userId, price);
} catch (RuntimeException e) {
logger.warn("balance branch failed: {}", e.getMessage());
throw new OrderFailedException("BALANCE_FAILED", e);
} Prevention
- Top up test users' balance before order storms; drained users deterministically fail here.
- Verify account service port 8083 and Seata server are up.
- Confirm all participants log the same XID so rollback spans services.
When it happens
Trigger: Order creation when the account service returns false — i.e., its reduce-balance failed with insufficient balance (errors 14/15). Requires account service on 127.0.0.1:8083 and the Seata infrastructure running.
Common situations: End-to-end rollback demo: once a test user's balance is drained, every subsequent order fails here, and observers should confirm the previously deducted stock and created order get rolled back. Pitfalls: wrong port (8083) or service not started; account service returning an error page (non-'true' body); missing XID propagation so the account deduction commits independently.
Related errors
AI-assisted analysis of yudaocode/SpringBoot-Labs@6c12efaed0 (2026-08-14).
Data as JSON: /api/errors/a80ceb0732e498e1.
Report an issue: GitHub.