Browse Source

fix: 结算确认增加条件更新门闩,并发重复确认不再双倍入账

- 原逻辑读状态→加余额→改状态无锁,并发重复确认同一结算单会把可提现余额加两次
- 改为条件更新(status 待结算→已结算)判影响行数,第二个事务直接失败
- 状态更新前移作为门闩,余额转入与平台费记录只执行一次

Co-Authored-By: Claude <noreply@anthropic.com>
skyline 3 weeks ago
parent
commit
980ff6b712

+ 11 - 6
car-wash-service/src/main/java/com/kym/service/impl/SettlementServiceImpl.java

@@ -216,6 +216,17 @@ public class SettlementServiceImpl extends MyBaseServiceImpl<SettlementRecordMap
             throw new IllegalArgumentException("仅待结算记录可确认");
         }
 
+        // 幂等门闩:条件更新(仅待结算可确认),并发重复确认时第二个事务更新 0 行直接失败,
+        // 余额转入与平台费记录不会重复执行
+        boolean claimed = lambdaUpdate()
+                .set(SettlementRecord::getStatus, SettlementRecord.STATUS_已结算)
+                .eq(SettlementRecord::getId, recordId)
+                .eq(SettlementRecord::getStatus, SettlementRecord.STATUS_待结算)
+                .update();
+        if (!claimed) {
+            throw new IllegalArgumentException("该记录已确认,不可重复操作");
+        }
+
         // 转入站点可提现余额
         stationAccountService.lambdaUpdate()
                 .setSql("available_balance = available_balance + {0}", record.getSettlementAmount())
@@ -228,12 +239,6 @@ public class SettlementServiceImpl extends MyBaseServiceImpl<SettlementRecordMap
             platformAccountService.addRevenue(record.getPlatformFee());
         }
 
-        // 更新状态为已结算
-        lambdaUpdate()
-                .set(SettlementRecord::getStatus, SettlementRecord.STATUS_已结算)
-                .eq(SettlementRecord::getId, recordId)
-                .update();
-
         log.info("结算确认完成,记录ID:{},站点:{},周期:{},金额:{} 分",
                 recordId, record.getStationId(), record.getSettlementPeriod(), record.getSettlementAmount());
     }