抢购活动使用redis加锁,造成商品卖不完的问题?

孤狼独闯天宇
  • 920
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,这会造成商品卖不完的现象。所以我觉得抢购获取不应该使用锁。
不知道大家有没有什么看法呢??

回复
阅读 621
2 个回答

看了你的操作,为什么要锁呢?

直接 incrby -1 如果的到的值大于等于0 就说明当前请求拿到了库存,继续往下发送订单事件.如果得到的值小于0 就说明当前请求没有拿到库存,返回抢购失败就可以了啊.

直接利用 incrby 的原子性来进行库存的操作就可以了啊.

不加锁是不可能的,超卖是比卖不完更严重的问题,没有锁就没法保证数量的一致性,就没法保证不超卖,卖不完的情况只能是在保证不超卖的情况下优化,比如减小锁粒度等等

楼上说的那个,基于incrby的原子性,明明这个命令是三个操作,先get,再加法,再写回,为什么就是原子操作了?还不是redis替你保证了并发安全。所以并非是没有加锁,只是redis替你做了,你就不用再自己实现。但这只是你的库存存到了redis才能这么做,如果存在mysql呢

你知道吗?

宣传栏