秒杀订单完成

This commit is contained in:
2025-07-03 15:31:48 +08:00
parent 6294765388
commit ce2db65128
3 changed files with 343 additions and 18 deletions

View File

@@ -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 "未知";
}
}
/**