redis防止抢购商品超卖

本文探讨了如何利用redis的特性解决抢购商品超卖问题。通过使用redis的list尝试解决,但发现并发请求时仍可能出现超卖。最终采用redis的incrby命令,利用其原子性特性确保并发请求时的正确计数,经过压力测试验证了这种方法的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

  • redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用。
  • 本篇文用来测试下使用redis来防止抢购商品超卖问题。

内容:

  • 使用redis的list进行测试

    思路是设置一个redis列表List,假设有十个商品,每次请求先判断List的长度,小于十就能抢到商品,将用户信息存放到List中。代码如下

 //进行抢购
    protected function way_list(){
        $num = $this->redis->lLen();
        if($this->redis->lLen()>=self::AMOUNTLIMIT){
            $this->writeLog("抢购失败".$num);
            return;
        }else{
            $this->redis->rPush($num);
            $this->writeLog("抢购成功".$num);
        }
    }

结果:失败!

可以很明显数量不对顺序也不对。

分析了下原因,在代码执行时,多用户并发请求时,第一个用户判断List长度符合条件还未进行List写入时,第二个用户也通过了List长度判断。所以就导致执行失败。

这就没有利用到redis的原子性

所以进行了改良

  • 使用redis 的incrby。incrby将制定key 的值增加指定的增量,并返回增量后的值。是一个原子性操作。所谓的原子性操作就是执行该方法后要嘛成功要嘛失败。

思路就是设置一个键值对存放被抢购数量,每次一个用户进来就将该值加一进行判断,如果小于抢购的商品数量则抢购成功,否则失败。代码如下

 protected function way_string(){
        //判断是否有初始化
        if(!$this->redis->exists(self::sold_name)){
            $this->redis->setnx(self::sold_name,0);
        }
        if($this->redis->incrby(self::sold_name,1) > self::AMOUNTLIMIT){
            $this->writeLog('失败');
        }else{
            $this->writeLog('成功');
        }
    }

结果

压力测试了几次都没有出现问题

通过apache自带的ab压力测试,进行五百次连接请求,并发三百次,没有出现超卖行为。

总结:会出现超卖主要是由于用户在请求的时候,代码在执行是有先后,会导致执行结果不符合预期。而采用redis的原子性就能避免。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩淼燃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值