@Service
public class SeckillService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private OrderService orderService;
/**
* 初始化库存
*/
public void initStock(String productId, int stock) {
String key = "seckill:stock:" + productId;
redisTemplate.opsForValue().set(key, String.valueOf(stock));
}
/**
* 秒杀下单
*/
public boolean seckill(String userId, String productId, int count) {
String stockKey = "seckill:stock:" + productId;
String userKey = "seckill:user:" + productId + ":" + userId;
// 1. 检查用户是否已购买(防止重复下单)
Boolean hasBought = redisTemplate.hasKey(userKey);
if (Boolean.TRUE.equals(hasBought)) {
throw new BusinessException("您已经参与过该商品的秒杀");
}
// 2. Lua 脚本原子扣减库存
String script =
"local stock = redis.call('get', KEYS[1]) " +
"if not stock or tonumber(stock) < tonumber(ARGV[1]) then " +
" return 0 " +
"end " +
"redis.call('decrby', KEYS[1], ARGV[1]) " +
"redis.call('setex', KEYS[2], 86400, '1') " + // 标记用户已购买,24小时
"return 1";
Long result = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Arrays.asList(stockKey, userKey),
String.valueOf(count)
);
if (result == 1) {
// 3. 异步创建订单
asyncCreateOrder(userId, productId, count);
return true;
}
return false;
}
/**
* 异步创建订单
*/
@Async
private void asyncCreateOrder(String userId, String productId, int count) {
try {
orderService.createOrder(userId, productId, count);
} catch (Exception e) {
// 订单创建失败,回滚库存
String stockKey = "seckill:stock:" + productId;
redisTemplate.opsForValue().increment(stockKey, count);
log.error("Create order failed, rollback stock", e);
}
}
}