Browse Source

fix: 订单结算增加条件更新门闩,杜绝并发双重扣款

- 原幂等检查(先查 payStatus 再结算)存在竞态窗口,并发结算可双重扣减用户余额
- 改为条件更新(pay_status 未支付→已支付)判影响行数,第二个事务更新 0 行直接跳过
- 结算中途失败事务回滚,门闩随之回滚,可安全重试
- 同时修复了原逻辑:订单不存在时不再继续执行扣款

Co-Authored-By: Claude <noreply@anthropic.com>
skyline 3 tuần trước cách đây
mục cha
commit
47def8b074

+ 7 - 3
car-wash-service/src/main/java/com/kym/service/impl/OrderSettlementServiceImpl.java

@@ -59,9 +59,13 @@ public class OrderSettlementServiceImpl implements OrderSettlementService {
     public void settleOrder(WashOrder washOrder, OrderInfo orderInfo) {
         log.info("执行订单结算,订单:{},结算信息:{}", orderInfo.getOrder_id(), orderInfo);
 
-        // 幂等保护:重新加载订单并检查是否已结算
-        var freshOrder = washOrderService.lambdaQuery().eq(WashOrder::getId, washOrder.getId()).one();
-        if (freshOrder != null && Integer.valueOf(WashOrder.PAY_STATUS_已支付).equals(freshOrder.getPayStatus())) {
+        // 幂等门闩:条件更新占位(未支付 → 已支付),并发结算时第二个事务更新 0 行直接跳过
+        boolean claimed = washOrderService.lambdaUpdate()
+                .eq(WashOrder::getId, washOrder.getId())
+                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
+                .set(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
+                .update();
+        if (!claimed) {
             log.warn("订单:{},已结算,跳过重复结算", orderInfo.getOrder_id());
             return;
         }