初识”乐观锁“

解决超卖问题

解决思路:乐观锁

image-20231018172157343

乐观锁的实现
1.版本号法
  1. 在数据表中添加一个版本号字段(version),并且默认为0。
  2. 更新数据前,读取需要更新的数据行,并取得当前版本号。
  3. 更新时,携带版本号并将版本号+1。
  4. 执行更新时,指定更新条件为版本号等于读取到的版本号。
  5. 如果版本号相同,则更新成功,并将版本号加 1。
  6. 如果版本号不同,则更新失败,表示数据已经被其它线程修改。
  7. 更新失败的线程可以选择重试更新,重新读取版本号然后更新。

image-20231018172720437

2.CAS法(自旋锁)
  1. 获取当前共享变量的值A
  2. 根据A计算出一个新的变量值B
  3. 使用CAS操作Transaction,将变量值变更为B,只有当当前变量的值仍等于A时,CAS才会成功
  4. 如果CAS失败,说明其他线程已经更新了变量值,则当前线程可以重新获取变量值然后重试CAS操作

image-20231018172709488

改进乐观锁

问题:当线程1执行完毕后,库存stock变为99,当线程2变更库存时,发现当前线程之前查询库存stock为100,不等于99,于是认为线程不安全,停止执行。

改进:当线程2发现库存stock不符时,不应该立即停止线程,应该判断目前库存stock值是否符合现实(大于0),以此判断线程是否安全

image-20231018183454695

核心实现:

//5.扣减库存
        boolean isSuccess = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock", 0).update();

完整代码:

/**
     * 秒杀优惠券——超卖问题
     * @param voucherId
     * @return
     */
    @Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {
        //1.查询优惠券
        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
        //2.判断秒杀是否开始
        if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())) {
            //尚未开始
            return Result.fail("秒杀尚未开始!");
        }
        //3.判断秒杀是否结束
        if (seckillVoucher.getEndTime().isBefore(LocalDateTime.now())) {
            //秒杀结束
            return Result.fail("秒杀已经结束!");
        }

        //4.判断库存是否充足
        if (seckillVoucher.getStock() < 1) {
            return Result.fail("库存不足!");
        }
        //5.扣减库存
        boolean isSuccess = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock", 0).update();
        if (!isSuccess) {
            return Result.fail("库存不足");
        }
        //6.创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //6.1订单ID
        long orderId = redisWorker.nextId("order");
        voucherOrder.setId(orderId);
        //6.2用户ID
        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //6.3代金券ID
        voucherOrder.setVoucherId(voucherId);
        //将订单存储到数据库
        save(voucherOrder);
        //7.返回订单id
        return Result.ok(orderId);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值