From 58d7ec90b08a1b19e5d8236a292b96dd8807fa0f Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Mon, 19 Oct 2026 17:44:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E9=AB=98=E8=AE=A2=E5=8D=95=E6=BA=90?= =?UTF-8?q?=E7=9A=84=E6=9F=A5=E8=AF=A2=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/OracleUpstreamOrderMapper.java | 8 +- .../price/oracle/TabOrderMonitorService.java | 224 ++++++++++++++++-- .../price/OracleUpstreamOrderMapper.xml | 34 ++- 3 files changed, 233 insertions(+), 33 deletions(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java index 6c25d790..a145f934 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java @@ -22,12 +22,18 @@ public interface OracleUpstreamOrderMapper long countTabOrderMonitor(@Param("orderTable") String orderTable, @Param("query") TabOrderMonitorQuery query); - List> selectTabOrderMonitorPage( + /** Key-first page for customer+time queries (sort narrow columns only). */ + List> selectTabOrderMonitorKeyPage( @Param("orderTable") String orderTable, @Param("query") TabOrderMonitorQuery query, @Param("startRow") long startRow, @Param("endRow") long endRow); + /** List detail by ids: display columns only. */ + List> selectTabOrderMonitorListByIds( + @Param("orderTable") String orderTable, + @Param("ids") List ids); + /** Distinct product codes for product-vs-package check (grouped, no pagination). */ List> selectTabOrderProductCodes( @Param("orderTable") String orderTable, diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java index 52cdd4c6..13462c55 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java @@ -61,6 +61,12 @@ public class TabOrderMonitorService /** 收集结果缓存条目上限(LRU 淘汰),避免不同单号集合无限占内存。 */ private static final int COLLECT_CACHE_MAX_ENTRIES = 20; + /** + * 客户+时间列表:一次拉取的主键上限。一次取齐后内存分页,总数稳定; + * 超过此数量仅展示前 N 条(避免 COUNT / 翻页估总数导致「共 101→201」)。 + */ + private static final int FILTER_LIST_KEY_LIMIT = 2000; + /** 单批 Oracle 查询最长等待(从库 socketTimeout 为 120s,留同样余量)。 */ private static final long COLLECT_BATCH_TIMEOUT_SECONDS = 120L; @@ -102,6 +108,19 @@ public class TabOrderMonitorService } }); + /** 客户+时间列表主键缓存(与单号收集缓存分开,存 ID 列表)。 */ + private final Map filterIdCache = + Collections.synchronizedMap(new LinkedHashMap(16, 0.75f, true) + { + private static final long serialVersionUID = 1L; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > COLLECT_CACHE_MAX_ENTRIES; + } + }); + private static final class CacheEntry { private final List keys; @@ -114,6 +133,18 @@ public class TabOrderMonitorService } } + private static final class FilterIdCacheEntry + { + private final List ids; + private final long expireAt; + + private FilterIdCacheEntry(List ids, long expireAt) + { + this.ids = ids; + this.expireAt = expireAt; + } + } + @PreDestroy public void shutdownCollectPool() { @@ -253,21 +284,8 @@ public class TabOrderMonitorService Long.valueOf(System.currentTimeMillis() - t0)); return new TabOrderPageResult(keys.size(), rows); } - long total; - try - { - PageHelper.clearPage(); - total = oracleUpstreamOrderMapper.countTabOrderMonitor(table, query); - } - catch (RuntimeException e) - { - throw new ServiceException("Oracle TAB_ORDER count failed: " + e.getMessage()); - } - finally - { - PageHelper.clearPage(); - } - return new TabOrderPageResult(total, doSelectRownumPage(table, query, pn, ps)); + // Customer+time: collect keys once (capped), memory-page; stable total (no 101->201). + return doSelectFilterListPage(table, query, pn, ps); } @DataSource(DataSourceType.SLAVE) @@ -338,27 +356,103 @@ public class TabOrderMonitorService private List doSelectRownumPage(String table, TabOrderMonitorQuery query, int pn, int ps) { - return toVoList(doSelectRownumRows(table, query, pn, ps)); + return doSelectFilterListPage(table, query, pn, ps).getRows(); + } + + /** + * Customer+time list: pull up to {@link #FILTER_LIST_KEY_LIMIT} keys once (cached), + * then memory-page and load display rows by ID. Total stays stable across pages. + */ + private TabOrderPageResult doSelectFilterListPage(String table, TabOrderMonitorQuery query, int pn, int ps) + { + long t0 = System.currentTimeMillis(); + List allIds = doCollectFilterKeyIds(table, query); + int total = allIds.size(); + int from = (pn - 1) * ps; + if (from >= total) + { + log.info("oracle tab_order filter-list customerSize={} begin={} end={} page={}/{} rows=0 total={} costMs={}", + query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(), + query.getBeginTime(), query.getEndTime(), pn, ps, Integer.valueOf(total), + Long.valueOf(System.currentTimeMillis() - t0)); + return new TabOrderPageResult(total, Collections.emptyList()); + } + List slice = allIds.subList(from, Math.min(from + ps, total)); + List list = loadListVosByIds(table, new ArrayList(slice)); + log.info("oracle tab_order filter-list customerSize={} begin={} end={} page={}/{} rows={} total={} costMs={}", + query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(), + query.getBeginTime(), query.getEndTime(), pn, ps, + Integer.valueOf(list.size()), Integer.valueOf(total), + Long.valueOf(System.currentTimeMillis() - t0)); + return new TabOrderPageResult(total, list); + } + + /** Collect (and cache) filter-path primary keys, newest first, capped at FILTER_LIST_KEY_LIMIT. */ + private List doCollectFilterKeyIds(String table, TabOrderMonitorQuery query) + { + String fingerprint = "filter|" + collectFingerprint(table, query); + FilterIdCacheEntry cached = filterIdCache.get(fingerprint); + long now = System.currentTimeMillis(); + if (cached != null && cached.expireAt > now) + { + return new ArrayList(cached.ids); + } + // Fetch limit+1 to detect cap; keep at most FILTER_LIST_KEY_LIMIT. + List ids = selectKeyIds(table, query, 0L, FILTER_LIST_KEY_LIMIT + 1L); + if (ids.size() > FILTER_LIST_KEY_LIMIT) + { + log.warn("oracle tab_order filter-list capped at {} keys (customer+time window too large); narrow pickup range", + Integer.valueOf(FILTER_LIST_KEY_LIMIT)); + ids = new ArrayList(ids.subList(0, FILTER_LIST_KEY_LIMIT)); + } + filterIdCache.put(fingerprint, new FilterIdCacheEntry(Collections.unmodifiableList(ids), + now + COLLECT_CACHE_TTL_MS)); + return new ArrayList(ids); } private List doSelectRownumRows(String table, TabOrderMonitorQuery query, int pn, int ps) { long endRow = (long) pn * ps; long startRow = endRow - ps; + long t0 = System.currentTimeMillis(); + List ids = selectKeyIds(table, query, startRow, endRow); + List rows = loadFullRowsByIds(table, ids); + log.info("oracle tab_order sync-page customerSize={} begin={} end={} page={}/{} rows={} costMs={}", + query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(), + query.getBeginTime(), query.getEndTime(), pn, ps, + Integer.valueOf(rows.size()), Long.valueOf(System.currentTimeMillis() - t0)); + return rows; + } + + private List selectKeyIds(String table, TabOrderMonitorQuery query, long startRow, long endRow) + { try { PageHelper.clearPage(); - long t0 = System.currentTimeMillis(); - List> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorPage(table, query, startRow, endRow); - log.info("oracle tab_order page customerSize={} begin={} end={} page={}/{} rows={} costMs={}", - query.getCustomerCodes() == null ? 0 : query.getCustomerCodes().size(), - query.getBeginTime(), query.getEndTime(), pn, ps, - rows == null ? 0 : rows.size(), System.currentTimeMillis() - t0); - return wrapRows(rows); + List> keys = + oracleUpstreamOrderMapper.selectTabOrderMonitorKeyPage(table, query, startRow, endRow); + if (keys == null || keys.isEmpty()) + { + return Collections.emptyList(); + } + List ids = new ArrayList(keys.size()); + for (Map key : keys) + { + Object idVal = value(key, "ID"); + if (idVal != null) + { + String id = String.valueOf(idVal).trim(); + if (!id.isEmpty()) + { + ids.add(id); + } + } + } + return ids; } catch (RuntimeException e) { - throw new ServiceException("Oracle TAB_ORDER list failed: " + e.getMessage()); + throw new ServiceException("Oracle TAB_ORDER key page failed: " + e.getMessage()); } finally { @@ -366,6 +460,88 @@ public class TabOrderMonitorService } } + private List loadListVosByIds(String table, List ids) + { + if (ids == null || ids.isEmpty()) + { + return Collections.emptyList(); + } + try + { + PageHelper.clearPage(); + List> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorListByIds(table, ids); + Map> rowById = indexRowsById(rows); + List list = new ArrayList(ids.size()); + for (String id : ids) + { + Map row = rowById.get(id); + if (row != null) + { + list.add(toVo(row)); + } + } + return list; + } + catch (RuntimeException e) + { + throw new ServiceException("Oracle TAB_ORDER list by ids failed: " + e.getMessage()); + } + finally + { + PageHelper.clearPage(); + } + } + + private List loadFullRowsByIds(String table, List ids) + { + if (ids == null || ids.isEmpty()) + { + return Collections.emptyList(); + } + try + { + PageHelper.clearPage(); + List> rows = oracleUpstreamOrderMapper.selectTabOrderMonitorByIds(table, ids); + Map> rowById = indexRowsById(rows); + List> ordered = new ArrayList>(ids.size()); + for (String id : ids) + { + Map row = rowById.get(id); + if (row != null) + { + ordered.add(row); + } + } + return wrapRows(ordered); + } + catch (RuntimeException e) + { + throw new ServiceException("Oracle TAB_ORDER list by ids failed: " + e.getMessage()); + } + finally + { + PageHelper.clearPage(); + } + } + + private static Map> indexRowsById(List> rows) + { + Map> rowById = new LinkedHashMap>(); + if (rows == null) + { + return rowById; + } + for (Map row : rows) + { + Object idVal = value(row, "ID"); + if (idVal != null) + { + rowById.put(String.valueOf(idVal).trim(), row); + } + } + return rowById; + } + private static List wrapRows(List> rows) { if (rows == null || rows.isEmpty()) diff --git a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml index 8966effb..b75903a4 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml @@ -46,21 +46,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + - o.BL_PICKUP = 1 - AND o.ORDER_STATUS IN (3, 4, 5, 6, 7, 8, 11) - AND o.CUSTOMER_CODE IN + o.CUSTOMER_CODE IN #{code} + + 1 = 1 + AND o.PICKUP_DATE >= TO_TIMESTAMP(#{query.beginTime}, 'YYYY-MM-DD HH24:MI:SS') AND o.PICKUP_DATE <= TO_TIMESTAMP(#{query.endTime}, 'YYYY-MM-DD HH24:MI:SS') + AND o.BL_PICKUP = 1 + AND o.ORDER_STATUS IN (3, 4, 5, 6, 7, 8, 11) AND o.ORDER_ID = #{query.orderId} @@ -128,11 +132,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + SELECT ID FROM ( + SELECT inner_q.ID AS ID, ROWNUM AS rn FROM ( + SELECT /*+ FIRST_ROWS(${endRow}) */ o.ID, o.PICKUP_DATE, o.ORDER_ID FROM ${orderTable} o WHERE @@ -143,6 +150,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHERE rn > #{startRow} + + +