Browse Source

feat: 1.新增补偿接口,在新redis中重建option的缓存
2.调整供货的redis赋值

zhangwl 1 month ago
parent
commit
1e24b821ca

+ 8 - 0
src/main/java/zs/payment/controller/EweiShopGoodsController.java

@@ -66,6 +66,14 @@ public class EweiShopGoodsController {
     }
     }
 
 
     /**
     /**
+     * 补偿接口:从 DB 重建 SKU 库存缓存到云商城 Redis
+     */
+    @GetMapping("/migrateSkuStockToMallRedis")
+    public Result migrateSkuStockToMallRedis() {
+        return commodityProcureService.migrateSkuStockToMallRedis();
+    }
+
+    /**
      * 批量供货/停止供货:把本地商品推送到云商城,或停止供货
      * 批量供货/停止供货:把本地商品推送到云商城,或停止供货
      * issupply=1: 供货  issupply=0: 停止供货
      * issupply=1: 供货  issupply=0: 停止供货
      * 加入Redis分布式锁防止用户多次点击重复提交
      * 加入Redis分布式锁防止用户多次点击重复提交

+ 6 - 0
src/main/java/zs/payment/service/commodity/CommodityProcureService.java

@@ -46,4 +46,10 @@ public interface CommodityProcureService {
      * 批量清理 gd_desc 脏数据:扫描463供货中 gd_desc 含无效 nfs 链接的 SPU,按取消供货逻辑级联清理
      * 批量清理 gd_desc 脏数据:扫描463供货中 gd_desc 含无效 nfs 链接的 SPU,按取消供货逻辑级联清理
      */
      */
     Result cleanupInvalidGdDescSuppliedGoods();
     Result cleanupInvalidGdDescSuppliedGoods();
+
+    /**
+     * 补偿接口:从 DB 重建 SKU 库存缓存到云商城 Redis
+     * 将 b2c_goods_sku_in_online 表中的 option_id→skuId、skuId→库存 映射写入云商城 Redis
+     */
+    Result migrateSkuStockToMallRedis();
 }
 }

+ 56 - 6
src/main/java/zs/payment/service/commodity/impl/CommodityProcureServiceImpl.java

@@ -50,6 +50,7 @@ import zs.payment.mapper.flymall.B2cGoodsAttrMapper;
 import zs.payment.mapper.flymall.B2cGoodsSpuInOnlineMapper;
 import zs.payment.mapper.flymall.B2cGoodsSpuInOnlineMapper;
 import zs.payment.mapper.flymall.B2cGoodsStatusMapper;
 import zs.payment.mapper.flymall.B2cGoodsStatusMapper;
 import zs.payment.messages.KafkaProducer;
 import zs.payment.messages.KafkaProducer;
+import zs.payment.utils.MallRedisUtils;
 import zs.payment.utils.RedisUtils;
 import zs.payment.utils.RedisUtils;
 
 
 import java.io.File;
 import java.io.File;
@@ -110,6 +111,8 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
     @Autowired
     @Autowired
     private RedisUtils redisUtils;
     private RedisUtils redisUtils;
     @Autowired
     @Autowired
+    private MallRedisUtils mallRedisUtils;
+    @Autowired
     private B2cGoodsSpuInOnlineMapper b2cGoodsSpuInOnlineMapper;
     private B2cGoodsSpuInOnlineMapper b2cGoodsSpuInOnlineMapper;
     @Autowired
     @Autowired
     private B2cGoodsAttrMapper b2cGoodsAttrMapper;
     private B2cGoodsAttrMapper b2cGoodsAttrMapper;
@@ -1306,12 +1309,12 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
                 sku.setQyId(opt.getId() != null ? opt.getId().intValue() : null);
                 sku.setQyId(opt.getId() != null ? opt.getId().intValue() : null);
                 b2cGoodsSkuInOnlineService.save(sku);
                 b2cGoodsSkuInOnlineService.save(sku);
 
 
-                // Redis缓存:对应PHP _saveSku中的redis操作
+                // Redis缓存:对应PHP _saveSku中的redis操作,写入云商城Redis
                 if (sku.getSkuId() != null && opt.getId() != null) {
                 if (sku.getSkuId() != null && opt.getId() != null) {
                     try {
                     try {
                         String optionKey = "option_" + opt.getId().intValue();
                         String optionKey = "option_" + opt.getId().intValue();
-                        redisUtils.set(optionKey, String.valueOf(sku.getSkuId()));
-                        redisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
+                        mallRedisUtils.set(optionKey, String.valueOf(sku.getSkuId()));
+                        mallRedisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
                     } catch (Exception e) {
                     } catch (Exception e) {
                         log.warn("Redis缓存多规格SKU库存失败 gdId={}, optionId={}", gdId, opt.getId(), e);
                         log.warn("Redis缓存多规格SKU库存失败 gdId={}, optionId={}", gdId, opt.getId(), e);
                     }
                     }
@@ -1334,12 +1337,12 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
             sku.setUpdTime(now);
             sku.setUpdTime(now);
             b2cGoodsSkuInOnlineService.save(sku);
             b2cGoodsSkuInOnlineService.save(sku);
 
 
-            // Redis缓存:对应PHP _noSaleAttrSetSku中的redis操作
+            // Redis缓存:对应PHP _noSaleAttrSetSku中的redis操作,写入云商城Redis
             if (sku.getSkuId() != null) {
             if (sku.getSkuId() != null) {
                 try {
                 try {
                     String goodsKey = "goods_" + gdId;
                     String goodsKey = "goods_" + gdId;
-                    redisUtils.set(goodsKey, String.valueOf(sku.getSkuId()));
-                    redisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
+                    mallRedisUtils.set(goodsKey, String.valueOf(sku.getSkuId()));
+                    mallRedisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
                 } catch (Exception e) {
                 } catch (Exception e) {
                     log.warn("Redis缓存单SKU库存失败 gdId={}", gdId, e);
                     log.warn("Redis缓存单SKU库存失败 gdId={}", gdId, e);
                 }
                 }
@@ -1667,6 +1670,53 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
         return Result.success("gd_desc脏数据清理完成,清理 " + success + " 条,失败 " + fail + " 条");
         return Result.success("gd_desc脏数据清理完成,清理 " + success + " 条,失败 " + fail + " 条");
     }
     }
 
 
+    @Override
+    public Result migrateSkuStockToMallRedis() {
+        final int BATCH = 500;
+        int success = 0, fail = 0;
+        Integer cursorSkuId = 0;  // 按主键 sku_id 游标推进
+
+        log.info("开始 SKU 库存迁移到云商城 Redis");
+
+        while (true) {
+            List<B2cGoodsSkuInOnline> batch = b2cGoodsSkuInOnlineService.list(
+                    new LambdaQueryWrapper<B2cGoodsSkuInOnline>()
+                            .eq(B2cGoodsSkuInOnline::getIsDel, 0)
+                            .isNotNull(B2cGoodsSkuInOnline::getQyId)
+                            .eq(B2cGoodsSkuInOnline::getShopId,13537)
+                            .gt(B2cGoodsSkuInOnline::getQyId, 0)
+                            .gt(B2cGoodsSkuInOnline::getSkuId, cursorSkuId)
+                            .orderByAsc(B2cGoodsSkuInOnline::getSkuId)
+                            .last("LIMIT " + BATCH));
+
+            if (batch.isEmpty()) {
+                break;
+            }
+
+            for (B2cGoodsSkuInOnline sku : batch) {
+                cursorSkuId = sku.getSkuId();  // 无论成功失败都推进游标
+                try {
+                    // option_id → skuId 映射
+                    String optionKey = "option_" + sku.getQyId();
+                    mallRedisUtils.set(optionKey, String.valueOf(sku.getSkuId()));
+
+                    // skuId → 库存 映射
+                    mallRedisUtils.set(String.valueOf(sku.getSkuId()),
+                                       String.valueOf(sku.getGdStock()));
+                    success++;
+                } catch (Exception e) {
+                    fail++;
+                    log.warn("SKU库存迁移失败 skuId={}, qyId={}", sku.getSkuId(), sku.getQyId(), e);
+                }
+            }
+
+            log.info("SKU库存迁移进度:成功{},失败{},cursorSkuId={}", success, fail, cursorSkuId);
+        }
+
+        log.info("SKU库存迁移完成,成功{},失败{}", success, fail);
+        return Result.success(String.format("迁移完成:成功%d条,失败%d条", success, fail));
+    }
+
     /**
     /**
      * 更新货架商品数量并软删除货架商品(对应PHP updateshelfnumbygdid + delGoodsByShelvesId)
      * 更新货架商品数量并软删除货架商品(对应PHP updateshelfnumbygdid + delGoodsByShelvesId)
      */
      */

+ 59 - 0
src/main/java/zs/payment/utils/Redis.java

@@ -49,6 +49,46 @@ public class Redis {
         return val;
         return val;
     }
     }
     /**
     /**
+     * 集群模式(指定数据库)
+     * @param ipPorts Redis cluster addresses
+     * @param db Redis database index
+     * @param callback Redis callback
+     * @return callback result
+     */
+    public static <V> V withClusterDb(String ipPorts, int db, RedisCallback<V> callback) {
+        String[] ipPortArray = ipPorts.split(",");
+        String ipPort = "";
+        if (ipPortArray.length > 0) {
+            Random random = new Random();
+            int index = random.nextInt(ipPortArray.length);
+            ipPort = ipPortArray[index];
+        }
+        JedisPool pool = poolClusterDb(ipPort, db);
+        Jedis jedis = null;
+        V val = null;
+
+        try {
+            for (int i = 1; i <= 2; i++) {
+                if (jedis == null) {
+                    if (i > 1) {
+                        Thread.sleep(200);
+                    }
+                    jedis = pool.getResource();
+                }
+            }
+            if (callback != null) {
+                val = callback.execute(jedis);
+            }
+        } catch (Exception e) {
+            log.error("redis " + ipPort + " db" + db, e);
+            returnResource(pool, jedis);
+        } finally {
+            returnResource(pool, jedis);
+        }
+        return val;
+    }
+
+    /**
      * 集群模式
      * 集群模式
      * @param ipPorts Redis cluster addresses
      * @param ipPorts Redis cluster addresses
      * @param callback Redis callback
      * @param callback Redis callback
@@ -161,6 +201,25 @@ public class Redis {
         return pool;
         return pool;
     }
     }
 
 
+    private static JedisPool poolClusterDb(String ipPort, int db) {
+        String poolKey = ipPort + "#db" + db;
+        JedisPool pool = pools.get(poolKey);
+        if (pool == null) {
+            String host = null;
+            int port = 6379;
+            String[] hp = ipPort.split(":");
+            if (hp.length > 0) {
+                host = hp[0];
+                if (hp.length > 1 && Pattern.matches("[0-9]+", hp[1])) {
+                    port = Integer.parseInt(hp[1]);
+                }
+            }
+            pool = new JedisPool(poolConfigCluster, host, port, 2000, null, db);
+            pools.put(poolKey, pool);
+        }
+        return pool;
+    }
+
     public static void returnResource(JedisPool jedisPool, Jedis jedis) {
     public static void returnResource(JedisPool jedisPool, Jedis jedis) {
         if (jedisPool != null && jedis != null) {
         if (jedisPool != null && jedis != null) {
             jedisPool.returnResource(jedis);
             jedisPool.returnResource(jedis);

+ 4 - 0
src/main/resources/application-pro.yml

@@ -69,6 +69,10 @@ supply:
 
 
 mall:
 mall:
     host: http://mall.zhongsou.com/qiyueapi/api
     host: http://mall.zhongsou.com/qiyueapi/api
+    # 云商城 Redis(SKU库存缓存等,对应 PHP 云商城侧 redis db3)
+    redis:
+        master: r-2zel7t7rnqxzhuk6yj.redis.rds.aliyuncs.com:6379
+        db: 3
     # 商品详情 NFS 文件存储(对应 PHP _writeText)
     # 商品详情 NFS 文件存储(对应 PHP _writeText)
     nfs:
     nfs:
         base-path: /data01/cloudmall/nfs          # NFS 挂载后的物理根目录(对应 PHP WEB_ROOT/nfs)
         base-path: /data01/cloudmall/nfs          # NFS 挂载后的物理根目录(对应 PHP WEB_ROOT/nfs)