秒杀订单完成
This commit is contained in:
@@ -111,6 +111,16 @@ public class FlashSaleService {
|
||||
redisService.delete(stockKey); // 先删除可能存在的异常数据
|
||||
redisService.setString(stockKey, flashSale.getFlashStock().toString()); // 确保存储为字符串数字
|
||||
|
||||
// 验证库存设置是否成功
|
||||
String verifyStock = redisService.getString(stockKey);
|
||||
log.info("秒杀活动库存初始化验证: flashSaleId={}, stockKey={}, setStock={}, actualStock={}",
|
||||
flashSale.getId(), stockKey, flashSale.getFlashStock(), verifyStock);
|
||||
|
||||
if (!flashSale.getFlashStock().toString().equals(verifyStock)) {
|
||||
log.error("库存初始化失败: flashSaleId={}, expected={}, actual={}",
|
||||
flashSale.getId(), flashSale.getFlashStock(), verifyStock);
|
||||
}
|
||||
|
||||
log.info("秒杀活动创建成功: ID={}", flashSale.getId());
|
||||
|
||||
return buildFlashSaleDTO(flashSale, product);
|
||||
@@ -178,18 +188,70 @@ public class FlashSaleService {
|
||||
currentStock = redisService.getString(stockKey);
|
||||
log.info("修复后库存: flashSaleId={}, stockKey={}, currentStock={}",
|
||||
flashSale.getId(), stockKey, currentStock);
|
||||
|
||||
// 如果修复后仍然为空,直接设置库存
|
||||
if (currentStock == null || currentStock.trim().isEmpty()) {
|
||||
log.error("库存修复失败,直接重新设置库存: flashSaleId={}, stock={}",
|
||||
flashSale.getId(), flashSale.getFlashStock());
|
||||
redisService.setString(stockKey, flashSale.getFlashStock().toString());
|
||||
currentStock = redisService.getString(stockKey);
|
||||
log.info("强制设置库存后: flashSaleId={}, stockKey={}, currentStock={}",
|
||||
flashSale.getId(), stockKey, currentStock);
|
||||
}
|
||||
}
|
||||
|
||||
// 最终验证库存数据有效性
|
||||
currentStock = redisService.getString(stockKey);
|
||||
if (currentStock == null || currentStock.trim().isEmpty()) {
|
||||
log.error("库存数据最终验证失败: flashSaleId={}, stockKey={}", flashSale.getId(), stockKey);
|
||||
return createFailResult("秒杀活动库存初始化失败,请稍后重试");
|
||||
}
|
||||
|
||||
// 使用Lua脚本原子性扣减库存
|
||||
log.info("准备执行秒杀脚本: stockKey={}, quantity={}, userId={}",
|
||||
stockKey, participateDTO.getQuantity(), userId);
|
||||
log.info("准备执行秒杀脚本: stockKey={}, quantity={}, userId={}, currentStock={}",
|
||||
stockKey, participateDTO.getQuantity(), userId, currentStock);
|
||||
Long remainingStock = redisService.executeFlashSaleScript(stockKey, participateDTO.getQuantity());
|
||||
log.info("秒杀脚本执行完成: stockKey={}, remainingStock={}", stockKey, remainingStock);
|
||||
|
||||
if (remainingStock < 0) {
|
||||
if (remainingStock == -1) {
|
||||
log.warn("秒杀库存key不存在或数据异常: flashSaleId={}, stockKey={}", flashSale.getId(), stockKey);
|
||||
return createFailResult("秒杀活动库存信息异常,请刷新页面重试");
|
||||
|
||||
// 自动修复数据并重试一次
|
||||
log.info("开始自动修复库存数据: flashSaleId={}", flashSale.getId());
|
||||
try {
|
||||
repairFlashSaleStock(flashSale.getId());
|
||||
|
||||
// 修复后重新验证库存
|
||||
String repairedStock = redisService.getString(stockKey);
|
||||
if (repairedStock != null && !repairedStock.trim().isEmpty()) {
|
||||
log.info("库存修复成功,重新执行秒杀脚本: flashSaleId={}, stock={}",
|
||||
flashSale.getId(), repairedStock);
|
||||
|
||||
// 重新执行秒杀脚本
|
||||
Long retryResult = redisService.executeFlashSaleScript(stockKey,
|
||||
participateDTO.getQuantity());
|
||||
log.info("修复后重试结果: flashSaleId={}, result={}", flashSale.getId(), retryResult);
|
||||
|
||||
if (retryResult >= 0) {
|
||||
// 修复后重试成功,继续正常流程
|
||||
remainingStock = retryResult;
|
||||
} else {
|
||||
// 重试仍然失败
|
||||
if (retryResult == -2) {
|
||||
return createFailResult("商品已售罄");
|
||||
} else {
|
||||
return createFailResult("系统繁忙,请稍后重试");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("库存修复失败: flashSaleId={}", flashSale.getId());
|
||||
return createFailResult("系统繁忙,请稍后重试");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("自动修复库存失败: flashSaleId={}", flashSale.getId(), e);
|
||||
return createFailResult("系统繁忙,请稍后重试");
|
||||
}
|
||||
} else if (remainingStock == -2) {
|
||||
log.info("秒杀库存不足: flashSaleId={}, 剩余库存不足", flashSale.getId());
|
||||
return createFailResult("商品已售罄");
|
||||
@@ -378,7 +440,17 @@ public class FlashSaleService {
|
||||
redisService.delete(stockKey); // 先删除可能存在的异常数据
|
||||
redisService.setString(stockKey, flashSale.getFlashStock().toString()); // 确保存储为字符串数字
|
||||
|
||||
log.info("秒杀活动预热完成: {}", flashSaleId);
|
||||
// 验证预热是否成功
|
||||
String verifyStock = redisService.getString(stockKey);
|
||||
log.info("秒杀活动预热验证: flashSaleId={}, stockKey={}, setStock={}, actualStock={}",
|
||||
flashSaleId, stockKey, flashSale.getFlashStock(), verifyStock);
|
||||
|
||||
if (!flashSale.getFlashStock().toString().equals(verifyStock)) {
|
||||
log.error("秒杀活动预热失败: flashSaleId={}, expected={}, actual={}",
|
||||
flashSaleId, flashSale.getFlashStock(), verifyStock);
|
||||
} else {
|
||||
log.info("秒杀活动预热完成: flashSaleId={}, stock={}", flashSaleId, verifyStock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,23 +517,108 @@ public class FlashSaleService {
|
||||
public void preloadAllActiveFlashSales() {
|
||||
log.info("开始预热所有活跃秒杀活动库存");
|
||||
|
||||
List<FlashSale> activeFlashSales = flashSaleRepository.findAll();
|
||||
try {
|
||||
// 获取所有秒杀活动(包括未开始、进行中的)
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<FlashSale> activeFlashSales = flashSaleRepository.findAll();
|
||||
|
||||
for (FlashSale flashSale : activeFlashSales) {
|
||||
try {
|
||||
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSale.getId();
|
||||
|
||||
// 使用set方法先存储,让系统能识别
|
||||
redisService.set(stockKey, flashSale.getFlashStock());
|
||||
|
||||
log.info("预热秒杀活动库存: flashSaleId={}, stock={}",
|
||||
flashSale.getId(), flashSale.getFlashStock());
|
||||
} catch (Exception e) {
|
||||
log.error("预热秒杀活动库存失败: flashSaleId={}", flashSale.getId(), e);
|
||||
if (activeFlashSales.isEmpty()) {
|
||||
log.info("没有找到任何秒杀活动,跳过预热");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("所有活跃秒杀活动库存预热完成");
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
|
||||
for (FlashSale flashSale : activeFlashSales) {
|
||||
try {
|
||||
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSale.getId();
|
||||
|
||||
// 检查活动状态,只预热有效的活动
|
||||
if (flashSale.getStatus() == 3) { // 已结束的活动跳过
|
||||
log.debug("跳过已结束的秒杀活动: flashSaleId={}", flashSale.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 验证库存数据有效性
|
||||
if (flashSale.getFlashStock() == null || flashSale.getFlashStock() < 0) {
|
||||
log.warn("秒杀活动库存数据无效,跳过: flashSaleId={}, stock={}",
|
||||
flashSale.getId(), flashSale.getFlashStock());
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查当前Redis中的库存
|
||||
String currentStock = redisService.getString(stockKey);
|
||||
log.debug("预热前检查库存: flashSaleId={}, stockKey={}, currentStock={}",
|
||||
flashSale.getId(), stockKey, currentStock);
|
||||
|
||||
// 如果库存已存在且有效,不重复设置
|
||||
if (currentStock != null && !currentStock.trim().isEmpty()) {
|
||||
try {
|
||||
Integer existingStock = Integer.parseInt(currentStock.trim());
|
||||
if (existingStock >= 0 && existingStock <= flashSale.getFlashStock()) {
|
||||
log.debug("库存已存在且有效,跳过设置: flashSaleId={}, existingStock={}",
|
||||
flashSale.getId(), existingStock);
|
||||
successCount++;
|
||||
continue;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("现有库存格式异常,将重新设置: flashSaleId={}, currentStock={}",
|
||||
flashSale.getId(), currentStock);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除可能存在的异常数据
|
||||
redisService.delete(stockKey);
|
||||
|
||||
// 设置库存数据 - 确保存储为字符串数字
|
||||
redisService.setString(stockKey, flashSale.getFlashStock().toString());
|
||||
|
||||
// 验证设置是否成功
|
||||
String verifyStock = redisService.getString(stockKey);
|
||||
if (flashSale.getFlashStock().toString().equals(verifyStock)) {
|
||||
log.info("预热秒杀活动库存成功: flashSaleId={}, stock={}, status={}",
|
||||
flashSale.getId(), flashSale.getFlashStock(), getStatusText(flashSale.getStatus()));
|
||||
successCount++;
|
||||
} else {
|
||||
log.error("预热秒杀活动库存验证失败: flashSaleId={}, expected={}, actual={}",
|
||||
flashSale.getId(), flashSale.getFlashStock(), verifyStock);
|
||||
failCount++;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("预热秒杀活动库存失败: flashSaleId={}", flashSale.getId(), e);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("所有秒杀活动库存预热完成: 总数={}, 成功={}, 失败={}",
|
||||
activeFlashSales.size(), successCount, failCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("预热所有秒杀活动库存时发生异常", e);
|
||||
throw new RuntimeException("预热秒杀活动库存失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态文本描述
|
||||
*/
|
||||
private String getStatusText(Integer status) {
|
||||
if (status == null) return "未知";
|
||||
switch (status) {
|
||||
case 1:
|
||||
return "未开始";
|
||||
case 2:
|
||||
return "进行中";
|
||||
case 3:
|
||||
return "已结束";
|
||||
case 4:
|
||||
return "已暂停";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user