抢购活动使用redis加锁,造成商品卖不完的问题?
public SeckillActivityRequestVO seckillHandle(SeckillActivityRequestVO request) {
SeckillActivityRequestVO response;
String key = "key:" + request.getSeckillId;
try {
Boolean lockFlag = redisTemplate.opsForValue().setIfAbsent(key, "val", 10, TimeUnit.SECONDS);
if (lockFlag) {
// HTTP请求用户服务进行用户相关的校验
// 用户活动校验
// 库存校验
Object stock = redisTemplate.opsForHash().get(key+":info", "stock");
assert stock != null;
if (Integer.parseInt(stock.toString()) <= 0) {
// 业务异常
} else {
redisTemplate.opsForHash().increment(key+":info", "stock", -1);
// 生成订单
// 发布订单创建成功事件
// 构建响应VO
}
}
} finally {
// 释放锁
stringRedisTemplate.delete("key");
// 构建响应VO
}
return response;
}
很显然,上面的代码,如果是在高并发下,大量的请求其实是获取不到锁,返回的response都是null,这会造成商品卖不完的现象。所以我觉得抢购获取不应该使用锁。
不知道大家有没有什么看法呢??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看了你的操作,为什么要锁呢?
直接 incrby -1 如果的到的值大于等于0 就说明当前请求拿到了库存,继续往下发送订单事件.如果得到的值小于0 就说明当前请求没有拿到库存,返回抢购失败就可以了啊.
直接利用 incrby 的原子性来进行库存的操作就可以了啊.
不加锁是不可能的,超卖是比卖不完更严重的问题,没有锁就没法保证数量的一致性,就没法保证不超卖,卖不完的情况只能是在保证不超卖的情况下优化,比如减小锁粒度等等
楼上说的那个,基于incrby的原子性,明明这个命令是三个操作,先get,再加法,再写回,为什么就是原子操作了?还不是redis替你保证了并发安全。所以并非是没有加锁,只是redis替你做了,你就不用再自己实现。但这只是你的库存存到了redis才能这么做,如果存在mysql呢