在高并发的情况下,利用redis来处理库存超卖和遗留问题

                在高并发的情况下,利用redis来处理库存超卖和遗留问题

首先现在redis中放上商品的库存数量为100间商品,在初始化一个set集合用于放秒杀成功的用户id,本用例先放进去一个id=10000的用户。

 

 @RequestMapping("skill")
    @ResponseBody
    public String kill(HttpServletRequest request){

        String userId=new Random().nextInt(50000)+"";
        String productId="0101";
        boolean b=doSkill(productId,userId);
        return "";

    }

    private boolean doSkill(String productId, String userId) {
        Jedis jedis = redisUtil.getJedis();
        String kcKey="Seckill:"+productId+":kc";
        String userKey="Seckill:"+productId+":user";
        String s    = jedis.get(kcKey);
        if (null==s){
            System.out.println("秒杀还么开始");
            jedis.close();
            return false;
        }
        //秒杀已经成功不能再次秒杀
        if (jedis.sismember(userKey,userId))
        {
            System.out.println("秒杀已经成功不能再次秒杀");
            jedis.close();
            return false;
        }
        if (Integer.parseInt(s)<=0)
        {
            System.out.println("秒杀结束");
            jedis.close();
            return false;
        }

        //减库存,家人
        jedis.decr(kcKey);
        jedis.sadd(userKey,userId);
        jedis.close();


        return true;
    }

下面进行压力测试(使用ab工具,具体可百度,不在此做详细说明):

 从上图结果看明显超卖了。

 

下面解决超卖:主要加事务,更改两处代码

下图显示redis的数据明显没有超卖,但是会有库存遗留,本次数据量和并发量小才没有。

 

解决库存遗留:lua脚本解决

把库存容量加到200,再次请求结果如下图,明显出现了库存遗留

 

简单介绍下lua脚本:它类似于redis的事务具有一定的原子性,不会被其他命令插队,可以完成一些redis的事务的工作。

注意:redis的版本在2.6及以上的版本

 

 private void doSkillByScript(String uid,String prodid){
        Jedis jedis = redisUtil.getJedis();
        String secKillScript ="local userid=KEYS[1];\r\n" +
                "local prodid=KEYS[2];\r\n" +
                "local qtkey='Seckill:'..prodid..\":kc\";\r\n" +
                "local usersKey='Seckill:'..prodid..\":user\";\r\n" +
                "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" +
                "if tonumber(userExists)==1 then \r\n" +
                "   return 2;\r\n" +
                "end\r\n" +
                "local num= redis.call(\"get\" ,qtkey);\r\n" +
                "if tonumber(num)<=0 then \r\n" +
                "   return 0;\r\n" +
                "else \r\n" +
                "   redis.call(\"decr\",qtkey);\r\n" +
                "   redis.call(\"sadd\",usersKey,userid);\r\n" +
                "end\r\n" +
                "return 1" ;
    /*    String sha1=  jedis.scriptLoad(secKillScript);

        Object result= jedis.evalsha(sha1, 2, uid,prodid);*/
        Object result = jedis.eval(secKillScript, 2, uid, prodid);


        String reString=String.valueOf(result);
        if ("0".equals( reString )  ) {
            System.err.println("已抢空!!");
        }else if("1".equals( reString )  )  {
            System.out.println("抢购成功!!!!");
        }else if("2".equals( reString )  )  {
            System.err.println("该用户已抢过!!");
        }else{
            System.err.println("抢购异常!!");
        }
        jedis.close();
    }

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值