|
|
@@ -133,31 +133,6 @@ public class StockDeductService {
|
|
|
// 1. 参数校验(Java 8 Optional 空值处理)
|
|
|
Integer num = Optional.ofNullable(deductNum).orElse(1);
|
|
|
String stockKey = RedisConstant.STOCK_KEY_PREFIX + liveId + ":" + productId;
|
|
|
- String lockKey = RedisConstant.LOCK_KEY_PREFIX + liveId + ":" + productId;
|
|
|
-
|
|
|
- // 3. 尝试获取分布式锁(非阻塞重试,Java 8 Stream API 实现重试)
|
|
|
-// 3. 尝试获取分布式锁(优化:加入随机延迟,避免惊群效应)
|
|
|
- boolean isLockAcquired = IntStream.range(0, RedisConstant.LOCK_MAX_RETRY).anyMatch(retryCount -> {
|
|
|
- Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, userId, RedisConstant.LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
|
|
|
- if (Boolean.TRUE.equals(result)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- try {
|
|
|
- // 随机延迟:50ms~150ms,避免所有请求同时重试
|
|
|
- long randomDelay = RedisConstant.LOCK_RETRY_INTERVAL + new Random().nextInt(100);
|
|
|
- TimeUnit.MILLISECONDS.sleep(randomDelay);
|
|
|
- } catch (InterruptedException e) {
|
|
|
- Thread.currentThread().interrupt();
|
|
|
- return false;
|
|
|
- }
|
|
|
- return false;
|
|
|
- });
|
|
|
- // 4. 未获取到锁,直接返回失败
|
|
|
- if (!isLockAcquired) {
|
|
|
- System.err.println("商品" + productId + "获取锁失败,高并发限流中");
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
try {
|
|
|
// 5. 执行库存扣减Lua脚本(原子操作,防超卖)
|
|
|
// 新增日志:打印当前库存值和扣减数量
|
|
|
@@ -165,11 +140,7 @@ public class StockDeductService {
|
|
|
log.info("拿到锁成功 → 库存Key:{},当前库存值:{},扣减数量:{}", stockKey, currentStockStr, num);
|
|
|
|
|
|
// 执行库存扣减Lua脚本
|
|
|
- Long remainingStock = redisTemplate.execute(
|
|
|
- STOCK_DEDUCT_SCRIPT,
|
|
|
- Collections.singletonList(stockKey),
|
|
|
- 1
|
|
|
- );
|
|
|
+ Long remainingStock = redisTemplate.execute(STOCK_DEDUCT_SCRIPT, Collections.singletonList(stockKey), 1);
|
|
|
|
|
|
// 新增日志:打印Lua返回结果
|
|
|
log.info("Lua脚本返回值:{}", remainingStock);
|
|
|
@@ -199,10 +170,9 @@ public class StockDeductService {
|
|
|
log.info("商品{}扣减失败:{}", productId, errorMsg);
|
|
|
return false;
|
|
|
}
|
|
|
- } finally {
|
|
|
- // 7. 释放分布式锁(Lua脚本保证原子性,仅释放自己持有的锁)
|
|
|
- redisTemplate.execute(LOCK_RELEASE_SCRIPT, Collections.singletonList(lockKey), userId);
|
|
|
- log.info("商品{}锁释放成功,持有者:{}", productId, userId);
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("支付失败获取失败", e);
|
|
|
+ return false;
|
|
|
}
|
|
|
});
|
|
|
}
|