From 0ddbb4ec727ffce844ef672107e3410d84b1f11a Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期三, 30 九月 2026 09:42:08 +0800
Subject: [PATCH] feat: 业务编码改为随机16位数字并保证全系统唯一

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java                            |   11 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java                          |   11 +
 /dev/null                                                                                                          |  102 -----------------
 yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java                         |   11 +
 yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java                     |   11 +
 yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java                      |   87 ++++++++++++++
 yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java     |   11 +
 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java           |   50 +++++---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java |   11 +
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java                         |   11 +
 10 files changed, 181 insertions(+), 135 deletions(-)

diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
index c1045ac..e19d041 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
@@ -1,29 +1,30 @@
 package cn.iocoder.yudao.framework.common.util.number;
 
+import java.util.concurrent.ThreadLocalRandom;
+
 /**
  * 涓氬姟缂栫爜锛堝崟鎹彿 / 涓绘暟鎹紪鐮侊級鐢熸垚鐨勫叕鍏辩害瀹氥��
  *
- * <p>闇�姹傦細绯荤粺涓墍鏈夎嚜鍔ㄧ敓鎴愮殑涓氬姟缂栫爜缁熶竴涓恒��16 浣嶇函鏁板瓧銆嶏紝涓斿叏绯荤粺鍞竴锛堜换鎰忎袱鏉$紪鐮侀兘涓嶉噸澶嶏級銆�
+ * <p>闇�姹傦細绯荤粺涓墍鏈夎嚜鍔ㄧ敓鎴愮殑涓氬姟缂栫爜缁熶竴涓恒��16 浣嶇函鏁板瓧銆嶏紝涓�**闅忔満鐢熸垚銆佷笉浣跨敤鑷/椤哄簭**锛�
+ * 鍚屾椂淇濊瘉鍏ㄧ郴缁熷敮涓�锛堜换鎰忎袱鏉$紪鐮侀兘涓嶉噸澶嶏級銆�
  *
- * <p>瀹炵幇绾﹀畾锛氬叏绯荤粺鍏辩敤鍚屼竴涓� Redis 鑷 KEY锛坽@link #GLOBAL_SEQ_KEY}锛夛紝
- * 姣忔鐢熸垚鏃跺鍏舵墽琛� INCR 寰楀埌鍗曡皟閫掑鐨勫簭鍒楀彿锛屽啀宸﹁ˉ '0' 鍒� {@link #CODE_LENGTH} 浣嶃��
- * 鐢变簬鎵�鏈夌紪鐮侀兘鏉ヨ嚜鍚屼竴鏉¢�掑搴忓垪锛屾晠澶╃劧淇濊瘉銆屽叏绯荤粺鍞竴銆嶃��
- *
- * <p>娉ㄦ剰锛�
+ * <p>瀹炵幇绾﹀畾锛�
  * <ul>
- *     <li>璇� KEY 涓嶈缃繃鏈熸椂闂达紝閬垮厤杩囨湡褰掗浂瀵艰嚧閲嶅彿锛�</li>
- *     <li>Redis 鑻ュ彂鐢熸暟鎹涪澶� / 娓呯┖锛岄渶瑕佷粠鏁版嵁搴撶幇鏈夌紪鐮佺殑鏈�澶у�兼仮澶嶈鏁板櫒锛屽惁鍒欏彲鑳介噸鍙枫��</li>
+ *     <li>缂栫爜 = 闅忔満 16 浣嶆暟瀛楋紙鑼冨洿 0 ~ 10^16-1锛屽乏渚цˉ '0'锛夛紱</li>
+ *     <li>鍞竴鎬х敱 Redis 闆嗗悎 {@link #USED_SET_KEY} 鏌ラ噸淇濊瘉锛氶殢鏈虹敓鎴愬悗鍐欏叆闆嗗悎锛�
+ *         鍐欐垚鍔燂紙杩斿洖 1锛夎鏄庢病鐢ㄨ繃鎵嶉噰鐢紝鍚﹀垯閲嶈瘯锛�</li>
+ *     <li>鍚勭敓鎴愮偣锛氳 {@link #randomCode()} 涓� {@link #MAX_RETRY}銆�</li>
  * </ul>
+ *
+ * <p>娉ㄦ剰锛歊edis 闆嗗悎涓㈠け鍚庯紝鍘嗗彶缂栫爜鍙兘琚噸鏂伴殢鏈哄懡涓紱搴旂敤鍚姩鏃朵細灏嗗簱鍐呭凡鏈夌紪鐮�
+ * 閲嶆柊杞藉叆闆嗗悎锛堣 yudao-server 鐨勫惎鍔ㄥ厹搴曪級銆�
  */
 public class BizNoUtils {
 
     /**
-     * 鍏ㄧ郴缁熶笟鍔$紪鐮佺粺涓�浣跨敤鐨� Redis 鑷 KEY銆�
-     *
-     * <p>鎵�鏈夋ā鍧楋紙erp / crm / trade / aftersales / hrm / bpm / mes锛夊叡鐢ㄦ KEY锛�
-     * 浠ヤ繚璇併�屽叏绯荤粺鍞竴銆嶃��
+     * 宸蹭娇鐢ㄤ笟鍔$紪鐮佺殑 Redis 闆嗗悎 KEY锛岀敤浜庨殢鏈虹紪鐮佹煡閲嶏紝淇濊瘉鍏ㄧ郴缁熷敮涓�銆�
      */
-    public static final String GLOBAL_SEQ_KEY = "biz:seq_no:global";
+    public static final String USED_SET_KEY = "biz:code:used";
 
     /**
      * 涓氬姟缂栫爜鐨勬�婚暱搴︼細16 浣�
@@ -31,13 +32,24 @@
     public static final int CODE_LENGTH = 16;
 
     /**
-     * 灏嗚嚜澧炲簭鍒楀彿鏍煎紡鍖栦负 16 浣嶇函鏁板瓧缂栫爜锛堝乏渚цˉ '0'锛�
-     *
-     * @param seq 鑷搴忓垪鍙�
-     * @return 16 浣嶇函鏁板瓧缂栫爜
+     * 闅忔満缂栫爜鐨勭┖闂翠笂闄愶紙涓嶅惈锛夛細10^16
      */
-    public static String format(Long seq) {
-        return String.format("%0" + CODE_LENGTH + "d", seq);
+    private static final long CODE_SPACE = 10_000_000_000_000_000L;
+
+    /**
+     * 鐢熸垚闅忔満缂栫爜鏃剁殑鏈�澶ч噸璇曟鏁帮紙鍛戒腑宸茬敤缂栫爜鏃堕噸璇曪級
+     */
+    public static final int MAX_RETRY = 10;
+
+    /**
+     * 鐢熸垚涓�涓殢鏈� 16 浣嶇函鏁板瓧缂栫爜锛堝乏渚цˉ '0'锛夛紝**涓嶅仛鏌ラ噸**銆�
+     *
+     * <p>璋冪敤鏂归渶鑷鐢� {@link #USED_SET_KEY} 鏌ラ噸锛屽懡涓垯閲嶈瘯銆�
+     *
+     * @return 闅忔満 16 浣嶇函鏁板瓧缂栫爜
+     */
+    public static String randomCode() {
+        return String.format("%0" + CODE_LENGTH + "d", ThreadLocalRandom.current().nextLong(CODE_SPACE));
     }
 
 }
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
index f945f06..a07d9c0 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
@@ -34,8 +34,15 @@
      */
     public String generate(String prefix) {
         // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
index 4f4fcb1..1fe6485 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
@@ -27,8 +27,15 @@
      */
     public String generate(BpmModelMetaInfoVO.ProcessIdRule processIdRule) {
         // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
index 23dc84f..2978c75 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
@@ -47,8 +47,15 @@
      */
     public String generate(String prefix) {
         // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
index 1c332a1..965f8be 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
@@ -56,8 +56,15 @@
      */
     public String generate(String prefix) {
         // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
index fe10bb3..a934a53 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
@@ -135,8 +135,15 @@
      */
     public String generate(String prefix, int digits) {
         // 鍏ㄧ郴缁熷叡鐢ㄥ悓涓�鑷搴忓垪锛屼繚璇佺紪鐮併��16 浣嶇函鏁板瓧銆嶄笖鍏ㄧ郴缁熷敮涓�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
index 41564e1..b0a9318 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
@@ -23,8 +23,15 @@
      * @return 16 浣嶇函鏁板瓧缂栫爜
      */
     public String generate() {
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
index c4daea0..2e298cd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
@@ -100,8 +100,15 @@
                                 MesMdAutoCodeContext context) {
         // 闇�姹傦細鎵�鏈変笟鍔$紪鐮佺粺涓�涓恒��16 浣嶇函鏁板瓧銆嶏紝涓斿叏绯荤粺鍞竴銆�
         // 鍥犳涓嶅啀鎸夎鍒欏垎娈垫嫾瑁咃紙鍥哄畾瀛楃/鏃ユ湡娈典細甯﹀叆瀛楁瘝锛夛紝鏀逛负鍙栧叏绯荤粺缁熶竴鑷搴忓垪銆�
-        Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY);
-        return BizNoUtils.format(no);
+        // 闅忔満鐢熸垚 16 浣嶇函鏁板瓧缂栫爜锛屽苟鐢� Redis 闆嗗悎鏌ラ噸锛屼繚璇佸叏绯荤粺鍞竴锛堜笉浣跨敤鑷/椤哄簭锛�
+        for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) {
+            String code = BizNoUtils.randomCode();
+            Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code);
+            if (added != null && added > 0) {
+                return code;
+            }
+        }
+        throw new IllegalStateException("鐢熸垚鍞竴涓氬姟缂栫爜澶辫触锛岃閲嶈瘯");
     }
 
     /**
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java
new file mode 100644
index 0000000..8f538f3
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java
@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.server.framework.bizno;
+
+import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 宸茬敤涓氬姟缂栫爜闆嗗悎鍏滃簳鍒濆鍖栥��
+ *
+ * <p>涓氬姟缂栫爜涓恒�岄殢鏈� 16 浣嶇函鏁板瓧銆嶏紝鍞竴鎬ч潬 Redis 闆嗗悎锛坽@link BizNoUtils#USED_SET_KEY}锛夋煡閲嶃��
+ * 鑻� Redis 涓㈠け璇ラ泦鍚堬紝宸茬敓鎴愮殑鍘嗗彶缂栫爜浼氳"蹇樿"锛屼箣鍚庡彲鑳借閲嶆柊闅忔満鍛戒腑鑰岄噸鍙枫��
+ *
+ * <p>鍥犳锛氬惎鍔ㄦ椂鑻ュ彂鐜拌闆嗗悎 **涓嶅瓨鍦�**锛屽垯浠庢暟鎹簱涓壂鎻忔墍鏈変笟鍔$紪鐮佸垪閲岀殑
+ * 銆�16 浣嶇函鏁板瓧銆嶇紪鐮侊紝閲嶆柊杞藉叆闆嗗悎锛屾仮澶嶉槻閲嶈兘鍔涖��
+ *
+ * <p>璇存槑锛�
+ * <ul>
+ *     <li>浠呭湪闆嗗悎缂哄け鏃舵壂鎻忥紙姝e父鍚姩鏃犻澶栧紑閿�锛夛紱</li>
+ *     <li>best-effort锛屽け璐ュ彧鍛婅銆佷笉褰卞搷鍚姩锛�</li>
+ *     <li>鏃х殑甯﹀瓧姣嶇紪鐮佷細琚拷鐣ャ��</li>
+ * </ul>
+ */
+@Component
+@Slf4j
+public class BizCodeSetInitializer implements ApplicationRunner {
+
+    /** 闆嗗悎鍒濆鍖栨爣璁帮紙闈� 16 浣嶏紝涓嶄細涓庣湡瀹炵紪鐮佸啿绐侊級锛岀敤浜庡湪搴撳唴鏃犵紪鐮佹椂涔熸爣璁颁负宸插垵濮嬪寲 */
+    private static final String INIT_MARKER = "__initialized__";
+
+    private final StringRedisTemplate stringRedisTemplate;
+    private final JdbcTemplate jdbcTemplate;
+
+    public BizCodeSetInitializer(StringRedisTemplate stringRedisTemplate, DataSource dataSource) {
+        this.stringRedisTemplate = stringRedisTemplate;
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+    }
+
+    @Override
+    public void run(ApplicationArguments args) {
+        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(BizNoUtils.USED_SET_KEY))) {
+            log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 闆嗗悎宸插瓨鍦紝璺宠繃搴撳唴鎵弿");
+            return;
+        }
+        long start = System.currentTimeMillis();
+        long total = 0L;
+        try {
+            String schema = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class);
+            List<Map<String, Object>> columns = jdbcTemplate.queryForList(
+                    "SELECT table_name, column_name FROM information_schema.columns " +
+                            "WHERE table_schema = ? AND data_type IN ('varchar', 'char') " +
+                            "AND (column_name = 'no' OR column_name = 'code' OR column_name = 'temp_code' " +
+                            "     OR column_name LIKE '%\\_no' OR column_name LIKE '%\\_code')",
+                    schema);
+            for (Map<String, Object> column : columns) {
+                String table = String.valueOf(column.get("table_name"));
+                String col = String.valueOf(column.get("column_name"));
+                if (table.toLowerCase().startsWith("qrtz_") || table.toLowerCase().startsWith("act_")) {
+                    continue;
+                }
+                List<String> codes = jdbcTemplate.queryForList(
+                        "SELECT `" + col + "` FROM `" + table + "` WHERE `" + col + "` REGEXP '^[0-9]{"
+                                + BizNoUtils.CODE_LENGTH + "}$'",
+                        String.class);
+                if (!codes.isEmpty()) {
+                    stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, codes.toArray(new String[0]));
+                    total += codes.size();
+                }
+            }
+            // 鏍囪涓哄凡鍒濆鍖栵紝閬垮厤涓嬫鍚姩閲嶅鎵弿
+            stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, INIT_MARKER);
+            log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 闆嗗悎缂哄け锛屽凡杞藉叆搴撳唴 {} 涓紪鐮�", total);
+        } catch (Exception e) {
+            log.warn("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 鍒濆鍖栧け璐ワ紙涓嶅奖鍝嶅惎鍔級锛岃鎺掓煡", e);
+        } finally {
+            log.info("[run][宸茬敤缂栫爜闆嗗悎鍏滃簳] 搴撳唴鎵弿鑰楁椂 {} ms", System.currentTimeMillis() - start);
+        }
+    }
+
+}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizNoSeqInitializer.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizNoSeqInitializer.java
deleted file mode 100644
index 826b58d..0000000
--- a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizNoSeqInitializer.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cn.iocoder.yudao.server.framework.bizno;
-
-import cn.iocoder.yudao.framework.common.util.number.BizNoUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.stereotype.Component;
-
-import javax.sql.DataSource;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 涓氬姟缂栫爜璁℃暟鍣ㄥ厹搴曞垵濮嬪寲銆�
- *
- * <p>鍏ㄧ郴缁熺紪鐮佺粺涓�鐢� Redis 鐨勫叏灞�鑷 KEY锛坽@link BizNoUtils#GLOBAL_SEQ_KEY}锛夌敓鎴愶紝
- * 鐢ㄤ簬淇濊瘉銆�16 浣嶇函鏁板瓧 + 鍏ㄧ郴缁熷敮涓�銆嶃�備絾 Redis 鏄唴瀛樺瓨鍌紝鑻ヨ娓呯┖ / 涓㈠け锛�
- * 璇� KEY 浼氬綊闆讹紝浠� 1 閲嶆柊寮�濮嬶紝瀵艰嚧涓庡巻鍙茬紪鐮侀噸澶嶃��
- *
- * <p>鍥犳锛氬綋鍚姩鏃跺彂鐜拌 KEY **涓嶅瓨鍦�**锛堣鏄� Redis 涓㈠け杩囪鏁帮級锛�
- * 浠庢暟鎹簱涓壂鎻忔墍鏈変笟鍔$紪鐮佸垪鐨勬渶澶у�硷紝鎶婅鏁板櫒鎭㈠鍒拌鏈�澶у�硷紝閬垮厤閲嶅彿銆�
- *
- * <p>璇存槑锛�
- * <ul>
- *     <li>浠呭湪 KEY 缂哄け鏃舵壂鎻忥紙姝e父鍚姩鏃犻澶栧紑閿�锛夛紱</li>
- *     <li>鎵弿鏄� best-effort锛屽け璐ュ彧鍛婅銆佷笉褰卞搷鍚姩锛�</li>
- *     <li>鍙粺璁°��16 浣嶇函鏁板瓧銆嶇殑缂栫爜锛屾棫鐨勫甫瀛楁瘝缂栫爜浼氳蹇界暐銆�</li>
- * </ul>
- */
-@Component
-@Slf4j
-public class BizNoSeqInitializer implements ApplicationRunner {
-
-    private final StringRedisTemplate stringRedisTemplate;
-    private final JdbcTemplate jdbcTemplate;
-
-    public BizNoSeqInitializer(StringRedisTemplate stringRedisTemplate, DataSource dataSource) {
-        this.stringRedisTemplate = stringRedisTemplate;
-        this.jdbcTemplate = new JdbcTemplate(dataSource);
-    }
-
-    @Override
-    public void run(ApplicationArguments args) {
-        String current = stringRedisTemplate.opsForValue().get(BizNoUtils.GLOBAL_SEQ_KEY);
-        if (current != null) {
-            log.info("[run][涓氬姟缂栫爜璁℃暟鍣ㄥ厹搴昡 Redis 璁℃暟宸插瓨鍦�({})锛岃烦杩囧簱鍐呮壂鎻�", current);
-            return;
-        }
-        long start = System.currentTimeMillis();
-        try {
-            long maxDb = computeMaxCodeInDb();
-            stringRedisTemplate.opsForValue().set(BizNoUtils.GLOBAL_SEQ_KEY, String.valueOf(maxDb));
-            log.info("[run][涓氬姟缂栫爜璁℃暟鍣ㄥ厹搴昡 Redis 璁℃暟缂哄け锛屽凡浠庡簱鍐呮渶澶х紪鐮佹仮澶嶄负 {}", maxDb);
-        } catch (Exception e) {
-            log.warn("[run][涓氬姟缂栫爜璁℃暟鍣ㄥ厹搴昡 鍒濆鍖栧け璐ワ紙涓嶅奖鍝嶅惎鍔級锛岃鎺掓煡", e);
-        } finally {
-            log.info("[run][涓氬姟缂栫爜璁℃暟鍣ㄥ厹搴昡 搴撳唴鎵弿鑰楁椂 {} ms", System.currentTimeMillis() - start);
-        }
-    }
-
-    /**
-     * 鎵弿搴撳唴鎵�鏈夊彲鑳藉瓨鏀句笟鍔$紪鐮佺殑鍒楋紝杩斿洖銆�16 浣嶇函鏁板瓧銆嶇紪鐮佺殑鏈�澶у�笺��
-     */
-    private long computeMaxCodeInDb() {
-        String schema = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class);
-        // 鎵惧嚭鎵�鏈� varchar/char 涓斿悕瀛楀儚缂栫爜鐨勫垪锛坣o / code / *_no / *_code / temp_code锛�
-        List<Map<String, Object>> columns = jdbcTemplate.queryForList(
-                "SELECT table_name, column_name FROM information_schema.columns " +
-                        "WHERE table_schema = ? AND data_type IN ('varchar', 'char') " +
-                        "AND (column_name = 'no' OR column_name = 'code' OR column_name = 'temp_code' " +
-                        "     OR column_name LIKE '%\\_no' OR column_name LIKE '%\\_code')",
-                schema);
-        if (columns.isEmpty()) {
-            return 0L;
-        }
-        StringBuilder sql = new StringBuilder("SELECT MAX(v) FROM (");
-        boolean first = true;
-        for (Map<String, Object> column : columns) {
-            String table = String.valueOf(column.get("table_name"));
-            String col = String.valueOf(column.get("column_name"));
-            // 璺宠繃 Quartz 妗嗘灦琛紝閬垮厤鏃犲叧鎵弿
-            if (table.toLowerCase().startsWith("qrtz_") || table.toLowerCase().startsWith("act_")) {
-                continue;
-            }
-            if (!first) {
-                sql.append(" UNION ALL ");
-            }
-            first = false;
-            sql.append("SELECT MAX(CAST(`").append(col).append("` AS UNSIGNED)) AS v FROM `").append(table)
-                    .append("` WHERE `").append(col).append("` REGEXP '^[0-9]{").append(BizNoUtils.CODE_LENGTH).append("}$'");
-        }
-        if (first) {
-            return 0L;
-        }
-        sql.append(") t");
-        Long max = jdbcTemplate.queryForObject(sql.toString(), Long.class);
-        return max == null ? 0L : max;
-    }
-
-}

--
Gitblit v1.9.3