redis优惠卷秒杀

思路

业务代码

  @Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {
        //查询优惠卷
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //判断秒杀是否开始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            //秒杀尚未开始
            return Result.fail("秒杀尚未开始,请耐心等待");
        }
        //判断秒杀是否结束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            //秒杀已经结束
            return Result.fail("本次秒杀已经结束");
        }
        //秒杀处于正常时间段
        //判断库存是否充足
        if (voucher.getStock()<1) {
            //库存不足
            return Result.fail("本次秒杀已经被抢完");
        }
        //库存充足
        //扣减库存
        boolean update = iSeckillVoucherService.update().setSql("stock = stock - 1").eq("voucher_id", voucherId).update();
        //判断库存扣减是否成功
        if (!update) {
            //库存扣减失败,返回信息
            return Result.fail("库存不足");
        }
        //库存扣减成功,添加订单信息
        VoucherOrder voucherOrder = new VoucherOrder();
        //添加订单id
            //使用订单生成器生成id
        long id = redisIdWorker.nextId("order");
        voucherOrder.setId(id);
        //添加用户id
            //从拦截器中获取
        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //添加消费卷id
        voucherOrder.setVoucherId(voucherId);
        //添加到数据库
        boolean save = this.save(voucherOrder);
        if (!save){
            //添加失败
            return Result.fail("下单失败");
        }
        return Result.ok(id);
    }

出现的问题,多线程并发冲突,会导致多卖

引入概念乐观锁悲观锁,悲观锁为强制所有线程串行执行,会导致效率低下

乐观锁

1.版本号法

2.CAS法

 

 利用CAS后代码

 @Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {
        //查询优惠卷
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //判断秒杀是否开始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            //秒杀尚未开始
            return Result.fail("秒杀尚未开始,请耐心等待");
        }
        //判断秒杀是否结束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            //秒杀已经结束
            return Result.fail("本次秒杀已经结束");
        }
        //秒杀处于正常时间段
        //判断库存是否充足
        if (voucher.getStock()<1) {
            //库存不足
            return Result.fail("本次秒杀已经被抢完");
        }
        //库存充足
        //扣减库存
        boolean update = iSeckillVoucherService.update().setSql("stock = stock - 1")
                .eq("voucher_id", voucherId)
                .eq("stock",voucher.getStock())
                .update();
        //判断库存扣减是否成功
        if (!update) {
            //库存扣减失败,返回信息
            return Result.fail("库存不足");
        }
        //库存扣减成功,添加订单信息
        VoucherOrder voucherOrder = new VoucherOrder();
        //添加订单id
            //使用订单生成器生成id
        long id = redisIdWorker.nextId("order");
        voucherOrder.setId(id);
        //添加用户id
            //从拦截器中获取
        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //添加消费卷id
        voucherOrder.setVoucherId(voucherId);
        //添加到数据库
        boolean save = this.save(voucherOrder);
        if (!save){
            //添加失败
            return Result.fail("下单失败");
        }
        return Result.ok(id);
    }

改进后发现成功率大幅下降预期成功率在0.5实际成功率0.2(乐观锁的弊端)

改进方法不在进行判断数量是否与开始查询到的数量一致,改进行判断数量是否大于0

代码

@Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {
        //查询优惠卷
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //判断秒杀是否开始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            //秒杀尚未开始
            return Result.fail("秒杀尚未开始,请耐心等待");
        }
        //判断秒杀是否结束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            //秒杀已经结束
            return Result.fail("本次秒杀已经结束");
        }
        //秒杀处于正常时间段
        //判断库存是否充足
        if (voucher.getStock()<1) {
            //库存不足
            return Result.fail("本次秒杀已经被抢完");
        }
        //库存充足
        //扣减库存
        boolean update = iSeckillVoucherService.update().setSql("stock = stock - 1")
                .eq("voucher_id", voucherId)
                .gt("stock",0)
                .update();
        //判断库存扣减是否成功
        if (!update) {
            //库存扣减失败,返回信息
            return Result.fail("库存不足");
        }
        //库存扣减成功,添加订单信息
        VoucherOrder voucherOrder = new VoucherOrder();
        //添加订单id
            //使用订单生成器生成id
        long id = redisIdWorker.nextId("order");
        voucherOrder.setId(id);
        //添加用户id
            //从拦截器中获取
        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //添加消费卷id
        voucherOrder.setVoucherId(voucherId);
        //添加到数据库
        boolean save = this.save(voucherOrder);
        if (!save){
            //添加失败
            return Result.fail("下单失败");
        }
        return Result.ok(id);
    }

测试(与预期结果一致)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值