优惠卷秒杀——一人一单

 

利用stringRedisTemplate生成唯一的id

package com.hmdp.service.impl;

import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorked;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@SuppressWarnings("all")
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
    @Autowired
    private ISeckillVoucherService seckillVoucherService;
    @Autowired
    private RedisIdWorked redisIdWorked;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 限时优惠卷的秒杀
     * @param voucherId
     * @return
     */

    @Override
    public Result seckillVoucher(Long voucherId) {
        //1.查询优惠卷
        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
        if(voucher==null){
            //该卷不存在
            return Result.fail("秒杀卷不存在");
        }
        //2.判断在秒杀开始前
        //得到秒杀开始时间
        LocalDateTime beginTime = voucher.getBeginTime();
        if (beginTime.isAfter(LocalDateTime.now())){
            //活动尚未开始
            return Result.ok("活动尚未开始");
        }
        //3.判断在秒杀开始后
        LocalDateTime endTime = voucher.getEndTime();
        if(endTime.isBefore(LocalDateTime.now())){
            return Result.ok("活动已经结束");
        }
        //4.判断库存是否充足
        Integer stock = voucher.getStock();
        if(stock<1){
            return Result.fail("库存不足");
        }
        UserDTO user = UserHolder.getUser();
        Long id = user.getId();
        SimpleRedisLock lock = new SimpleRedisLock("order:"+id,stringRedisTemplate);
        //尝试获取锁
        boolean flag = lock.tryLock(1200L);
        if(!flag){
            return Result.fail("一个人只能下一单");
        }
        try {
            //如果这个类本身调用是不具备管理事务的,如果使用Spring管理可以控制事务的一致性
            //获取一个spring的代理对象
            IVoucherOrderService proxy =(IVoucherOrderService) AopContext.currentProxy();
            //利用spring代理对象确保事务的一致性
            return proxy.createVoucherOrder(voucherId);
        } finally {
            //释放锁
            lock.unlock();
        }


    }

    @Transactional
    public Result createVoucherOrder(Long voucherId){
        //5.保证一人一单
        //5.1用户id
        UserDTO user = UserHolder.getUser();
        Long id = user.getId();
        Integer count = query().eq("user_id", id).eq("voucher_id", voucherId).count();
        if(count>0){
            return Result.fail("该用户已经购买");
        }
        //6.扣减库存
        seckillVoucherService.update().setSql("stock=stock-1")
                .eq("voucher_id",voucherId).gt("stock",0)//stock>0
                .update();
        //7.创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //7.1订单id
        long order = redisIdWorked.nextId("order");
        voucherOrder.setId(order);
        //7.2用户id
        voucherOrder.setUserId(id);
        //7.3购买代金卷的id
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        //8.返回订单id
        return Result.ok(order);
    }

}
@Autowired
private ISeckillVoucherService seckillVoucherService;
@Autowired
private RedisIdWorked redisIdWorked;
/**
 * 限时优惠卷的秒杀
 * @param voucherId
 * @return
 */
@Transactional//同时操作两张表 保持数据库的一致性
@Override
public Result seckillVoucher(Long voucherId) {
    //1.查询优惠卷
    SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
    if(voucher==null){
        //该卷不存在
        return Result.fail("秒杀卷不存在");
    }
    //2.判断在秒杀开始前
    //得到秒杀开始时间
    LocalDateTime beginTime = voucher.getBeginTime();
    if (beginTime.isAfter(LocalDateTime.now())){
        //活动尚未开始
        return Result.ok("活动尚未开始");
    }
    //3.判断在秒杀开始后
    LocalDateTime endTime = voucher.getEndTime();
    if(endTime.isBefore(LocalDateTime.now())){
        return Result.ok("活动已经结束");
    }
    //4.判断库存是否充足
    Integer stock = voucher.getStock();
    if(stock<1){
        return Result.fail("库存不足");
    }
    UserDTO user = UserHolder.getUser();
    Long id = user.getId();
    synchronized (id.toString().intern()){//toString会重新开辟一块空间加上intern()方法时会在常量池中找内容相同的字符串
        //如果这个类本身调用是不具备管理事务的,如果使用Spring管理可以控制事务的一致性
        //获取一个spring的代理对象
        IVoucherOrderService proxy =(IVoucherOrderService) AopContext.currentProxy();
        //利用spring代理对象确保事务的一致性
        return proxy.createVoucherOrder(voucherId);
    }

}

@Transactional
public Result createVoucherOrder(Long voucherId){
    //5.保证一人一单
    //5.1用户id
    UserDTO user = UserHolder.getUser();
    Long id = user.getId();
    Integer count = query().eq("user_id", id).eq("voucher_id", voucherId).count();
    if(count>0){
        return Result.fail("该用户已经购买");
    }
    //6.扣减库存
    seckillVoucherService.update().setSql("stock=stock-1")
            .eq("voucher_id",voucherId).gt("stock",0)//stock>0
            .update();
    //7.创建订单
    VoucherOrder voucherOrder = new VoucherOrder();
    //7.1订单id
    long order = redisIdWorked.nextId("order");
    voucherOrder.setId(order);
    //7.2用户id
    voucherOrder.setUserId(id);
    //7.3购买代金卷的id
    voucherOrder.setVoucherId(voucherId);
    save(voucherOrder);
    //8.返回订单id
    return Result.ok(order);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值