From 978caa640a45bd7a5b3089aa76204e451d517658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Mon, 28 Sep 2026 15:59:39 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=B6=E6=AC=BE=E6=B5=81=E6=B0=B4?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=94=B9=E4=B8=BA=E6=89=B9=E9=87=8F=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8E=E6=89=B9=E9=87=8F=E4=BF=9D=E5=AD=98=EF=BC=88?= =?UTF-8?q?N+1=E2=86=92=E6=89=B9=E9=87=8F=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReceiptFlowServiceImpl.java | 95 ++++++++++++++----- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java index 56f0dbad..8433fdc3 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceiptFlowServiceImpl.java @@ -346,53 +346,98 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl serialNumbers = new HashSet<>(); - int syncedCount = 0; - int createdCount = 0; - int updatedCount = 0; + // 第一遍:收集有效的 detailSerialNo,跳过无效数据 + Map validAnnounces = new LinkedHashMap<>(); for (BfiClaimAnnounceVO announce : announces) { - // 明细流水号为幂等键,缺省依次回退金蝶交易明细编号、银行流水号 String detailSerialNo = firstNonBlank(announce.getDetailid(), announce.getTradedetailno(), announce.getBankdetailno()); if (Func.isEmpty(detailSerialNo)) { log.warn("收款流水同步跳过:认领公告[{}]缺少明细流水号", announce.getBillno()); continue; } - if (!serialNumbers.add(detailSerialNo.trim())) { - throw new ServiceException("明细流水号" + detailSerialNo.trim() + "重复"); + detailSerialNo = detailSerialNo.trim(); + if (validAnnounces.containsKey(detailSerialNo)) { + throw new ServiceException("明细流水号" + detailSerialNo + "重复"); } - // 行级锁防并发:同一流水并发手动同步时避免重复落库或覆盖已认领状态 - KingdeeReceiptFlow entity = baseMapper.selectOne(Wrappers.lambdaQuery() - .eq(KingdeeReceiptFlow::getDetailSerialNo, detailSerialNo.trim()) - .last("FOR UPDATE")); - boolean created = entity == null; + BigDecimal receiptAmount = money(announce.getReamount()); + if (receiptAmount.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("收款流水同步跳过:认领公告[{}]收款金额为空或小于0", announce.getBillno()); + continue; + } + validAnnounces.put(detailSerialNo, announce); + } + + if (validAnnounces.isEmpty()) { + record(null, null, "sync", "手动同步流水", null, null, BigDecimal.ZERO, + "金蝶认领公告无有效数据"); + return 0; + } + + // 批量查询已存在的记录(FOR UPDATE 防并发) + List existingEntities = baseMapper.selectList( + Wrappers.lambdaQuery() + .in(KingdeeReceiptFlow::getDetailSerialNo, validAnnounces.keySet()) + .last("FOR UPDATE") + ); + Map existingMap = existingEntities.stream() + .collect(Collectors.toMap(KingdeeReceiptFlow::getDetailSerialNo, e -> e)); + + // 第二遍:构建新增和更新列表 + List toInsert = new ArrayList<>(); + List toUpdate = new ArrayList<>(); + int createdCount = 0; + int updatedCount = 0; + + for (Map.Entry entry : validAnnounces.entrySet()) { + String detailSerialNo = entry.getKey(); + BfiClaimAnnounceVO announce = entry.getValue(); + BigDecimal receiptAmount = money(announce.getReamount()); + + KingdeeReceiptFlow existing = existingMap.get(detailSerialNo); + boolean created = (existing == null); + + KingdeeReceiptFlow entity; if (created) { entity = new KingdeeReceiptFlow(); entity.setClaimedAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); entity.setClaimStatus(UNCLAIMED); + } else { + entity = existing; } - BigDecimal receiptAmount = money(announce.getReamount()); - if (receiptAmount.compareTo(BigDecimal.ZERO) <= 0) { - // 公告金额异常时跳过单条并告警,不阻断整批同步、不破坏已有流水 - log.warn("收款流水同步跳过:认领公告[{}]收款金额为空或小于0", announce.getBillno()); - continue; - } - copyAnnounceRow(entity, announce, detailSerialNo.trim(), receiptAmount); + + copyAnnounceRow(entity, announce, detailSerialNo, receiptAmount); entity.setClaimStatus(amountClaimStatus(money(entity.getClaimedAmount()), receiptAmount)); + if (created) { - baseMapper.insert(entity); + toInsert.add(entity); createdCount++; } else { - baseMapper.updateById(entity); + toUpdate.add(entity); updatedCount++; } - record(entity.getId(), null, "sync", created ? "新增金蝶收款流水" : "更新金蝶收款流水", - entity.getClaimStatus(), entity.getClaimStatus(), BigDecimal.ZERO, detailSerialNo.trim()); - syncedCount++; } + + // 批量插入和更新 + if (!toInsert.isEmpty()) { + saveBatch(toInsert); + } + if (!toUpdate.isEmpty()) { + updateBatchById(toUpdate); + } + + // 记录操作日志 + for (KingdeeReceiptFlow entity : toInsert) { + record(entity.getId(), null, "sync", "新增金蝶收款流水", + entity.getClaimStatus(), entity.getClaimStatus(), BigDecimal.ZERO, entity.getDetailSerialNo()); + } + for (KingdeeReceiptFlow entity : toUpdate) { + record(entity.getId(), null, "sync", "更新金蝶收款流水", + entity.getClaimStatus(), entity.getClaimStatus(), BigDecimal.ZERO, entity.getDetailSerialNo()); + } + log.info("金蝶收款流水同步完成 claimusers:{},拉取 {} 条,新增 {} 条,更新 {} 条", claimusers, announces.size(), createdCount, updatedCount); - return syncedCount; + return createdCount + updatedCount; } private Map candidateRow(FormalSettlement settlement) {