Browse Source

改造库存

吴树波 1 tuần trước cách đây
mục cha
commit
b9299800b9

+ 20 - 13
fs-common/src/main/java/com/fs/common/core/redis/service/StockDeductService.java

@@ -1,6 +1,7 @@
 package com.fs.common.core.redis.service;
 
 import com.fs.common.constant.RedisConstant;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
@@ -16,6 +17,7 @@ import java.util.stream.IntStream;
 /**
  * 高并发库存扣减服务(Java 8 + Redis分布式锁)
  */
+@Slf4j
 @Service
 public class StockDeductService {
 
@@ -54,7 +56,7 @@ public class StockDeductService {
     public void initStock(Long productId, Integer initStock) {
         String stockKey = RedisConstant.STOCK_KEY_PREFIX + productId;
         redisTemplate.opsForValue().set(stockKey, initStock, 24 * 60 * 60, TimeUnit.SECONDS);
-        System.out.println("商品" + productId + "库存初始化完成,初始库存:" + initStock);
+        log.info("商品" + productId + "库存初始化完成,初始库存:" + initStock);
     }
 
     /**
@@ -64,7 +66,7 @@ public class StockDeductService {
      * @param deductNum 扣减数量(默认1)
      * @return 扣减结果:true=成功,false=失败
      */
-    public CompletableFuture<Boolean> deductStockAsync(Long productId, Integer deductNum) {
+    public CompletableFuture<Boolean> deductStockAsync(Long productId, Integer deductNum, Long userId) {
         // Java 8 CompletableFuture 异步处理,提升高并发吞吐量
         return CompletableFuture.supplyAsync(() -> {
             // 1. 参数校验(Java 8 Optional 空值处理)
@@ -72,13 +74,10 @@ public class StockDeductService {
             String stockKey = RedisConstant.STOCK_KEY_PREFIX + productId;
             String lockKey = RedisConstant.LOCK_KEY_PREFIX + productId;
 
-            // 2. 生成锁持有者唯一标识(UUID + 线程ID,避免误释放)
-            String lockOwner = UUID.randomUUID().toString() + "-" + Thread.currentThread().getId();
-
             // 3. 尝试获取分布式锁(非阻塞重试,Java 8 Stream API 实现重试)
 // 3. 尝试获取分布式锁(优化:加入随机延迟,避免惊群效应)
             boolean isLockAcquired = IntStream.range(0, RedisConstant.LOCK_MAX_RETRY).anyMatch(retryCount -> {
-                Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, lockOwner, RedisConstant.LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
+                Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, userId, RedisConstant.LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
                 if (Boolean.TRUE.equals(result)) {
                     return true;
                 }
@@ -102,7 +101,7 @@ public class StockDeductService {
                 // 5. 执行库存扣减Lua脚本(原子操作,防超卖)
                 // 新增日志:打印当前库存值和扣减数量
                 Integer currentStockStr = (Integer) redisTemplate.opsForValue().get(stockKey);
-                System.out.println("拿到锁成功 → 库存Key:" + stockKey + ",当前库存值:" + currentStockStr + ",扣减数量:" + num);
+                log.info("拿到锁成功 → 库存Key:{},当前库存值:{},扣减数量:{}", stockKey, currentStockStr, num);
 
                 // 执行库存扣减Lua脚本
                 Long remainingStock = redisTemplate.execute(
@@ -112,20 +111,28 @@ public class StockDeductService {
                 );
 
                 // 新增日志:打印Lua返回结果
-                System.out.println("Lua脚本返回值:" + remainingStock);
+                log.info("Lua脚本返回值:{}", remainingStock);
 
                 // 6. 判断扣减结果
-                if (remainingStock != null && remainingStock >= 0) {
-                    System.out.println("商品" + productId + "库存扣减成功,剩余库存:" + remainingStock);
+                if (remainingStock >= 0) {
+                    log.info("商品{}库存扣减成功,剩余库存:{}", productId, remainingStock);
                     return true;
                 } else {
-                    System.err.println("商品" + productId + "库存不足,扣减失败");
+                    String errorMsg = "";
+                    switch (remainingStock.intValue()) {
+                        case -1: errorMsg = "库存不足"; break;
+                        case -2: errorMsg = "库存Key不存在"; break;
+                        case -3: errorMsg = "库存值非数字"; break;
+                        case -4: errorMsg = "扣减数量无效"; break;
+                        default: errorMsg = "未知错误,错误码:" + remainingStock;
+                    }
+                    log.info("商品{}扣减失败:{}", productId, errorMsg);
                     return false;
                 }
             } finally {
                 // 7. 释放分布式锁(Lua脚本保证原子性,仅释放自己持有的锁)
-                redisTemplate.execute(LOCK_RELEASE_SCRIPT, Collections.singletonList(lockKey), lockOwner);
-                System.out.println("商品" + productId + "锁释放成功,持有者:" + lockOwner);
+                redisTemplate.execute(LOCK_RELEASE_SCRIPT, Collections.singletonList(lockKey), userId);
+                log.info("商品{}锁释放成功,持有者:{}", productId, userId);
             }
         });
     }

+ 1 - 1
fs-user-app/src/test/java/com/fs/test/StockDeductTest.java

@@ -48,7 +48,7 @@ public class StockDeductTest {
 
         // 提交50万请求
         for (int i = 0; i < TOTAL_REQUESTS; i++) {
-            futureList.add(stockDeductService.deductStockAsync(PRODUCT_ID, 1));
+            futureList.add(stockDeductService.deductStockAsync(PRODUCT_ID, 1, (long) i));
         }
 
         // 等待所有任务完成(Java 8 CompletableFuture 批量处理)