模拟测试秒杀活动 Redisson 的作用

本文通过一个实例展示了在进行压力测试时,由于并发问题导致库存扣减错误。在没有使用Redisson的情况下,尽管测试显示成功,但实际库存处理存在线程安全问题。通过在方法上加`synchronized`关键字解决本地线程同步,但这无法解决分布式环境的并发问题。引入Redisson作为分布式锁,能够有效地解决多服务器、多线程组同时压测时的库存同步问题。

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

在没有用Redisson时,用jmeter做压力测试时出现的问题。库存设定为50,用5个线程去测

        测试代码

 //秒杀活动
    @GetMapping("buyItem")
    public Object getUserInfoByUserId(@RequestParam(value = "itemId",required = true) long item){
        RedissonRedis value = (RedissonRedis) RedisUtil.getValue(redisTemplate, CarownerhomeKeyName.buyShopItemInfo + item);
        long count= Long.parseLong(value.getItemCount());
        if (value==null ){
            return "商品不存在";
        }
        System.out.println("当前商品"+item+"的redis库存"+count);
        if (count > 0){
            //减库操作
            updateRedis(item);
            System.out.println("购买商品后"+item+"的mysql库存"+redissonService.getById(item).getItemCount());
            RedissonRedis value1 =(RedissonRedis) RedisUtil.getValue(redisTemplate, CarownerhomeKeyName.buyShopItemInfo + item);
            System.out.println("购买商品后"+item+"的redis库存"+value1.getItemCount());
        }

        return "购买成功";
    }

 public void updateRedis(long item){
        long countNew =0;
        try {
            RedissonRedis value =(RedissonRedis) RedisUtil.getValue(redisTemplate, CarownerhomeKeyName.buyShopItemInfo + item);
            System.out.println("--------当前商品"+item+"的redis库存"+value.getItemCount());
            long i= Long.parseLong(value.getItemCount());
            if (value != null && i>0){
                countNew=i-1;
            }else {
                throw new RRException("该商品库存不够了");
            }
            redissonService.updateById(item, String.valueOf(countNew));
            updateDbRedisNoLock(item);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw e;
        }

        压力测试显示成功 

         后台输出情况

        数据库情况

 

 根据后台输出情况,各个线程进来时拿到的库存都是50 ,就出现了问题。这里就需要到锁。

最简单的办法 是在方法上加上synchronized 关键字 给这个方法加上锁 让线程之间分开执行。

但是这个方法不能考虑锁住分布式的问题。当有布置多个服务器,有多个线程组同时压测时就有问题。

  这里用到redisson 就能解决这个问题

 //秒杀活动
    @GetMapping("buyItem")
    public Object getUserInfoByUserId(@RequestParam(value = "itemId",required = true) long item) throws Exception {
        //创建锁
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(String.valueOf(item));
        //创建写锁
        RLock rLock = readWriteLock.writeLock();
        //开启锁
        rLock.lock();
        try {
            RedissonRedis value = (RedissonRedis) RedisUtil.getValue(redisTemplate, CarownerhomeKeyName.buyShopItemInfo + item);
            long count= Long.parseLong(value.getItemCount());
            if (value==null ){
                return "商品不存在";
            }
            System.out.println("当前商品"+item+"的redis库存"+count);
            if (count > 0){
                //减库操作
                updateRedis(item);
                System.out.println("购买商品后"+item+"的mysql库存"+redissonService.getById(item).getItemCount());
                RedissonRedis value1 =(RedissonRedis) RedisUtil.getValue(redisTemplate, CarownerhomeKeyName.buyShopItemInfo + item);
                System.out.println("购买商品后"+item+"的redis库存"+value1.getItemCount());
            }
            return "购买成功";
        }catch (Exception e){
            System.out.println(e);
            throw new Exception();
        }finally {
            //关闭锁
            rLock.unlock();
        }

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值