基于synchronize乐观锁解决一人一单的并发安全问题

synchronize只锁定同一用户,生成代理对象是因为,this调用当前对象事务不生效,生成代理对象从而实现spring接管事务问题。

@Override
    public Result seckillVocher(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("库存不足!");
        }
        Long userId = UserHolder.getUser().getId();
        //返回字符串对象的规范表示,id值一样,锁定同一用户
        synchronized (userId.toString().intern()) {
            //获取代理对象(事务生效)
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);
        }
    }

 gt("stock", 0)

通过判断库存是否大于0来实现乐观锁,即使处于多线程时也不会出现超卖问题,缺点是增加了mysql负担 。

@Transactional
    public Result createVoucherOrder(Long voucherId) {
        //查询订单
        Long userId = UserHolder.getUser().getId();
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("用户已经购买过!");
        }
        //扣减库存
        Boolean success = iSeckillVoucherService.update()
                .setSql("stock = stock -1")
                .eq("voucher_id", voucherId).gt("stock", 0)
                .update();
        if (!success) {
            //扣减失败
            return Result.fail("库存不足!");
        }
        //创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        Long orderId = redisWorker.nextId("order");
        voucherOrder.setId(orderId);
        voucherOrder.setUserId(userId);
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        return Result.ok(orderId);
    }

在集群情况下会失效。

你可能感兴趣的:(1024程序员节)