修复文件

This commit is contained in:
2025-07-02 22:39:21 +08:00
parent 3b3ec8ea7d
commit b46312c428
21 changed files with 2233 additions and 650 deletions

View File

@@ -106,9 +106,10 @@ public class FlashSaleService {
// 缓存秒杀活动信息
cacheFlashSaleInfo(flashSale, product);
// 预热库存到Redis
// 预热库存到Redis - 确保存储为数字类型
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSale.getId();
redisService.set(stockKey, flashSale.getFlashStock());
redisService.delete(stockKey); // 先删除可能存在的异常数据
redisService.setString(stockKey, flashSale.getFlashStock().toString()); // 确保存储为字符串数字
log.info("秒杀活动创建成功: ID={}", flashSale.getId());
@@ -163,15 +164,42 @@ public class FlashSaleService {
}
try {
// 使用Lua脚本原子性扣减库存
// 检查并修复库存数据
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSale.getId();
String currentStock = redisService.getString(stockKey);
log.info("秒杀前库存检查: flashSaleId={}, stockKey={}, currentStock={}",
flashSale.getId(), stockKey, currentStock);
if (currentStock == null || currentStock.trim().isEmpty()) {
log.warn("检测到库存数据异常,尝试修复: flashSaleId={}", flashSale.getId());
repairFlashSaleStock(flashSale.getId());
// 修复后重新获取库存
currentStock = redisService.getString(stockKey);
log.info("修复后库存: flashSaleId={}, stockKey={}, currentStock={}",
flashSale.getId(), stockKey, currentStock);
}
// 使用Lua脚本原子性扣减库存
log.info("准备执行秒杀脚本: stockKey={}, quantity={}, userId={}",
stockKey, participateDTO.getQuantity(), userId);
Long remainingStock = redisService.executeFlashSaleScript(stockKey, participateDTO.getQuantity());
log.info("秒杀脚本执行完成: stockKey={}, remainingStock={}", stockKey, remainingStock);
if (remainingStock < 0) {
if (remainingStock == -1) {
return createFailResult("秒杀活动库存信息异常");
} else {
log.warn("秒杀库存key不存在或数据异常: flashSaleId={}, stockKey={}", flashSale.getId(), stockKey);
return createFailResult("秒杀活动库存信息异常,请刷新页面重试");
} else if (remainingStock == -2) {
log.info("秒杀库存不足: flashSaleId={}, 剩余库存不足", flashSale.getId());
return createFailResult("商品已售罄");
} else if (remainingStock == -3) {
log.error("秒杀参数异常: flashSaleId={}, quantity={}", flashSale.getId(),
participateDTO.getQuantity());
return createFailResult("参数异常,请检查购买数量");
} else {
log.error("秒杀脚本执行异常: flashSaleId={}, returnValue={}", flashSale.getId(), remainingStock);
return createFailResult("系统异常,请稍后重试");
}
}
@@ -345,13 +373,97 @@ public class FlashSaleService {
// 缓存秒杀活动信息
cacheFlashSaleInfo(flashSale, product);
// 预热库存
// 预热库存 - 确保存储为数字类型
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSaleId;
redisService.set(stockKey, flashSale.getFlashStock());
redisService.delete(stockKey); // 先删除可能存在的异常数据
redisService.setString(stockKey, flashSale.getFlashStock().toString()); // 确保存储为字符串数字
log.info("秒杀活动预热完成: {}", flashSaleId);
}
/**
* 修复Redis中的库存数据
*/
public void repairFlashSaleStock(Long flashSaleId) {
log.info("修复秒杀活动库存数据: {}", flashSaleId);
Optional<FlashSale> flashSaleOpt = flashSaleRepository.findById(flashSaleId);
if (!flashSaleOpt.isPresent()) {
log.warn("秒杀活动不存在: {}", flashSaleId);
return;
}
FlashSale flashSale = flashSaleOpt.get();
String stockKey = FLASH_SALE_STOCK_PREFIX + flashSaleId;
// 获取当前Redis中的库存值
String currentStock = redisService.getString(stockKey);
log.info("当前Redis库存值: key={}, value={}", stockKey, currentStock);
// 如果库存值无效,则重新设置
try {
if (currentStock == null || currentStock.trim().isEmpty()) {
log.warn("库存值为空,重新设置: key={}, resetTo={}", stockKey, flashSale.getFlashStock());
redisService.setString(stockKey, flashSale.getFlashStock().toString());
// 验证设置是否成功
String verifyStock = redisService.getString(stockKey);
log.info("库存设置验证: key={}, setTo={}, actualValue={}",
stockKey, flashSale.getFlashStock(), verifyStock);
} else {
Integer stockNumber = Integer.parseInt(currentStock.trim());
if (stockNumber < 0 || stockNumber > flashSale.getFlashStock()) {
log.warn("库存值异常,重新设置: key={}, currentValue={}, resetTo={}",
stockKey, currentStock, flashSale.getFlashStock());
redisService.setString(stockKey, flashSale.getFlashStock().toString());
// 验证设置是否成功
String verifyStock = redisService.getString(stockKey);
log.info("异常库存修复验证: key={}, setTo={}, actualValue={}",
stockKey, flashSale.getFlashStock(), verifyStock);
} else {
log.info("库存值正常: key={}, value={}", stockKey, stockNumber);
}
}
} catch (NumberFormatException e) {
log.error("库存值格式异常,重新设置: key={}, currentValue={}", stockKey, currentStock, e);
redisService.delete(stockKey);
redisService.setString(stockKey, flashSale.getFlashStock().toString());
// 验证设置是否成功
String verifyStock = redisService.getString(stockKey);
log.info("格式异常修复验证: key={}, setTo={}, actualValue={}",
stockKey, flashSale.getFlashStock(), verifyStock);
}
log.info("库存数据修复完成: {}", flashSaleId);
}
/**
* 重新预热所有活跃的秒杀活动库存
*/
public void preloadAllActiveFlashSales() {
log.info("开始预热所有活跃秒杀活动库存");
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);
}
}
log.info("所有活跃秒杀活动库存预热完成");
}
/**
* 获取秒杀活动剩余库存
*/
@@ -458,6 +570,165 @@ public class FlashSaleService {
return true;
}
/**
* 发布秒杀活动
*/
@Transactional
public FlashSaleDTO publishFlashSale(Long flashSaleId) {
log.info("发布秒杀活动: ID={}", flashSaleId);
// 获取现有秒杀活动
Optional<FlashSale> flashSaleOpt = flashSaleRepository.findById(flashSaleId);
if (!flashSaleOpt.isPresent()) {
throw new RuntimeException("秒杀活动不存在");
}
FlashSale flashSale = flashSaleOpt.get();
// 检查活动状态
if (flashSale.getStatus() != 1) {
throw new RuntimeException("只有未开始的秒杀活动才能发布");
}
// 验证时间
LocalDateTime now = LocalDateTime.now();
if (flashSale.getStartTime().isBefore(now)) {
throw new RuntimeException("开始时间不能早于当前时间");
}
if (flashSale.getStartTime().isAfter(flashSale.getEndTime())) {
throw new RuntimeException("开始时间不能晚于结束时间");
}
// 验证商品存在
Product product = productRepository.findById(flashSale.getProductId()).orElse(null);
if (product == null) {
throw new RuntimeException("关联商品不存在");
}
// 验证库存
if (flashSale.getFlashStock() <= 0) {
throw new RuntimeException("秒杀库存必须大于0");
}
// 预热缓存
preloadFlashSale(flashSaleId);
log.info("秒杀活动发布成功: ID={}", flashSaleId);
return buildFlashSaleDTO(flashSale, product);
}
/**
* 暂停秒杀活动
*/
@Transactional
public FlashSaleDTO pauseFlashSale(Long flashSaleId) {
log.info("暂停秒杀活动: ID={}", flashSaleId);
// 获取现有秒杀活动
Optional<FlashSale> flashSaleOpt = flashSaleRepository.findById(flashSaleId);
if (!flashSaleOpt.isPresent()) {
throw new RuntimeException("秒杀活动不存在");
}
FlashSale flashSale = flashSaleOpt.get();
// 检查活动状态
if (flashSale.getStatus() != 2) {
throw new RuntimeException("只有进行中的秒杀活动才能暂停");
}
// 更新状态为暂停 (status = 4)
flashSaleRepository.updateStatus(flashSaleId, 4);
flashSale.setStatus(4);
// 更新缓存
Product product = productRepository.findById(flashSale.getProductId()).orElse(null);
cacheFlashSaleInfo(flashSale, product);
log.info("秒杀活动暂停成功: ID={}", flashSaleId);
return buildFlashSaleDTO(flashSale, product);
}
/**
* 恢复秒杀活动
*/
@Transactional
public FlashSaleDTO resumeFlashSale(Long flashSaleId) {
log.info("恢复秒杀活动: ID={}", flashSaleId);
// 获取现有秒杀活动
Optional<FlashSale> flashSaleOpt = flashSaleRepository.findById(flashSaleId);
if (!flashSaleOpt.isPresent()) {
throw new RuntimeException("秒杀活动不存在");
}
FlashSale flashSale = flashSaleOpt.get();
// 检查活动状态
if (flashSale.getStatus() != 4) {
throw new RuntimeException("只有暂停的秒杀活动才能恢复");
}
// 检查是否已结束
LocalDateTime now = LocalDateTime.now();
if (flashSale.getEndTime().isBefore(now)) {
throw new RuntimeException("秒杀活动已结束,无法恢复");
}
// 更新状态为进行中 (status = 2)
flashSaleRepository.updateStatus(flashSaleId, 2);
flashSale.setStatus(2);
// 更新缓存
Product product = productRepository.findById(flashSale.getProductId()).orElse(null);
cacheFlashSaleInfo(flashSale, product);
log.info("秒杀活动恢复成功: ID={}", flashSaleId);
return buildFlashSaleDTO(flashSale, product);
}
/**
* 结束秒杀活动
*/
@Transactional
public FlashSaleDTO endFlashSale(Long flashSaleId) {
log.info("结束秒杀活动: ID={}", flashSaleId);
// 获取现有秒杀活动
Optional<FlashSale> flashSaleOpt = flashSaleRepository.findById(flashSaleId);
if (!flashSaleOpt.isPresent()) {
throw new RuntimeException("秒杀活动不存在");
}
FlashSale flashSale = flashSaleOpt.get();
// 检查活动状态
if (flashSale.getStatus() == 3) {
throw new RuntimeException("秒杀活动已经结束");
}
if (flashSale.getStatus() == 1) {
throw new RuntimeException("秒杀活动尚未开始,无法结束");
}
// 更新状态为已结束 (status = 3)
flashSaleRepository.updateStatus(flashSaleId, 3);
flashSale.setStatus(3);
// 清除相关缓存
clearFlashSaleCache(flashSaleId);
// 更新缓存
Product product = productRepository.findById(flashSale.getProductId()).orElse(null);
cacheFlashSaleInfo(flashSale, product);
log.info("秒杀活动结束成功: ID={}", flashSaleId);
return buildFlashSaleDTO(flashSale, product);
}
/**
* 更新秒杀活动状态
*/