소스 검색

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

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

Co-Authored-By: Claude <noreply@anthropic.com>
skyline 3 주 전
부모
커밋
47def8b074
1개의 변경된 파일7개의 추가작업 그리고 3개의 파일을 삭제
  1. 7 3
      car-wash-service/src/main/java/com/kym/service/impl/OrderSettlementServiceImpl.java

+ 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;
         }