diff --git a/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java b/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java index 828fa0e..968bdfc 100644 --- a/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java +++ b/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java @@ -149,6 +149,7 @@ public class CreditCompanyController extends BaseController { List errorMessages = new ArrayList<>(); int insertedCount = 0; Set touchedMatchNames = new HashSet<>(); + String refreshWarning = null; try { List list = null; @@ -324,13 +325,31 @@ public class CreditCompanyController extends BaseController { } } } - creditCompanyRecordCountService.refreshAll(touchedCompanyIds); + try { + creditCompanyRecordCountService.refreshAll(touchedCompanyIds); + } catch (Exception ex) { + // 导入本身已经成功写入,回填计数字段失败不应导致整个导入失败(可后续单独重试刷新)。 + String msg = ex.getMessage(); + if (msg != null && msg.length() > 300) { + msg = msg.substring(0, 300) + "..."; + } + refreshWarning = "关联记录数回填失败:" + (msg != null ? msg : ex.getClass().getSimpleName()); + ex.printStackTrace(); + } } if (errorMessages.isEmpty()) { - return success("成功入库" + insertedCount + "条数据", null); + String msg = "成功入库" + insertedCount + "条数据"; + if (refreshWarning != null) { + msg = msg + ";" + refreshWarning; + } + return success(msg, null); } else { - return success("导入完成,入库" + insertedCount + "条,失败" + errorMessages.size() + "条", errorMessages); + String msg = "导入完成,入库" + insertedCount + "条,失败" + errorMessages.size() + "条"; + if (refreshWarning != null) { + msg = msg + ";" + refreshWarning; + } + return success(msg, errorMessages); } } catch (Exception e) { diff --git a/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java b/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java index 0326a22..9cd21cc 100644 --- a/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java +++ b/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java @@ -82,16 +82,24 @@ public class CreditCompanyRecordCountService { } // 表/字段名来自固定枚举,不允许外部传入,避免 SQL 注入。 + // + // 这里不要用「UPDATE ... SET col=(SELECT COUNT... WHERE t.company_id=c.id)」的相关子查询: + // 如果关联表缺少 (company_id, deleted) 索引,会导致对每个 company_id 都进行一次全表扫描,极慢, + // 进而容易触发 JDBC/MySQL 侧的超时/断链(Communications link failure)。 + // + // 用聚合后再 JOIN 的方式:每个 chunk 只扫描一次关联表。 String sql = "" + "UPDATE credit_company c " - + "SET " + type.getCompanyColumn() + " = (" - + " SELECT COUNT(1) " - + " FROM " + type.getSourceTable() + " t " - + " WHERE t.company_id = c.id AND t.deleted = 0" - + ") " + + "LEFT JOIN (" + + " SELECT company_id, COUNT(1) AS cnt " + + " FROM " + type.getSourceTable() + " " + + " WHERE deleted = 0 AND company_id IN (:ids) " + + " GROUP BY company_id" + + ") t ON t.company_id = c.id " + + "SET c." + type.getCompanyColumn() + " = IFNULL(t.cnt, 0) " + "WHERE c.id IN (:ids)"; - final int inChunkSize = 1000; + final int inChunkSize = 500; for (int i = 0; i < ids.size(); i += inChunkSize) { List chunk = ids.subList(i, Math.min(ids.size(), i + inChunkSize)); namedJdbc.update(sql, new MapSqlParameterSource("ids", chunk)); diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 770ca87..7a1e639 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -459,6 +459,8 @@ public class GltTicketOrderServiceImpl extends ServiceImpl() + .eq(GltUserTicket::getTenantId, tenantId) + .eq(GltUserTicket::getDeleted, 0) + .eq(GltUserTicket::getId, ticketOrder.getUserTicketId()) + .last("limit 1") + ); + if (userTicket == null) { + return; + } + + Integer shopOrderId = userTicket.getOrderId(); + String shopOrderNo = userTicket.getOrderNo(); + if (shopOrderId == null && !StringUtils.hasText(shopOrderNo)) { + return; + } + + LambdaUpdateWrapper uw = new LambdaUpdateWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .and(w -> w.ne(ShopOrder::getOrderStatus, 1).or().isNull(ShopOrder::getOrderStatus)) + .set(ShopOrder::getOrderStatus, 1) + .set(ShopOrder::getUpdateTime, now); + if (shopOrderId != null) { + uw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + uw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + + boolean updated = shopOrderService.update(uw); + if (updated) { + return; + } + + // 幂等:若已是 1,则视为成功;否则记录日志便于排查关联关系/数据缺失 + LambdaQueryWrapper qw = new LambdaQueryWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .eq(ShopOrder::getOrderStatus, 1); + if (shopOrderId != null) { + qw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + qw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + if (shopOrderService.count(qw) <= 0) { + log.warn("送水订单完成但同步商城订单完成状态失败 - tenantId={}, ticketOrderId={}, shopOrderId={}, shopOrderNo={}", + tenantId, ticketOrderId, shopOrderId, shopOrderNo); + } + } + private void settleRiderCommissionIfEligible(Integer ticketOrderId, Integer tenantId, boolean requirePhoto) { if (ticketOrderId == null || tenantId == null) { return;