Redis
主页 > 数据库 > Redis >

Redis实现限量优惠券的秒杀功能

2024-12-04 | 佚名 | 点击:

核心:避免超卖问题,保证一人一单  业务逻辑

代码步骤分析

全部代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

@Service

public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource

    private ISeckillVoucherService seckillVoucherService;

    @Resource

    private RedisIdWorker redisIdWorker;

    @Resource

    private StringRedisTemplate stringRedisTemplate;

    @Resource

    private RedissonClient redissonClient;

    @Override

    public Result seckillVoucher(Long voucherId) {

        //1 查询优惠券信息

        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);

        //2 判断秒杀是否开始

        LocalDateTime now = LocalDateTime.now(); //现在时间

        LocalDateTime beginTime = seckillVoucher.getBeginTime(); //开始时间

        LocalDateTime endTime = seckillVoucher.getEndTime(); //结束时间

        if (now.isBefore(beginTime)) {

            return Result.fail("秒杀还未开始");

        }

        //3 判断秒杀是否结束

        if (now.isAfter(endTime)) {

            return Result.fail("秒杀已结束");

        }

        //4 判断库存是否充足

        int stock = (int) seckillVoucher.getStock();

        if (stock == 0 && stock <= 0) {

            return Result.fail("库存不足");

        }

        //确保一人一单 用户ID和代金券ID联合查询

        Long userId = UserHolder.getUser().getId();

        //先获取锁 再提交事务

        //synchronized (userId.toString().intern()) {

        //创建锁对象

        //SimpleRedisLock simpleRedisLock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);

        RLock lock = redissonClient.getLock("lock:order:" + userId);

        //获取锁

        boolean isLock = lock.tryLock();

        //判断是否获取锁成功

        if (!isLock){

            //获取锁失败 返回错误或失败

            return Result.fail("不允许重复下单");

        }

        try {

            //获取事务的代理对象

            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();

            return proxy.creatVoucherOrder(voucherId);

        } finally {

            //释放锁

            lock.unlock();

        }

        //}//事务提交之后在释放锁

    }

    /**

     * 这里对于加锁做出一些解释:如果锁加在整个方法上,那么就会导

     *  致锁的粒度过大,导致每个进程进来都会锁住,所以要控制锁的粒度

     */

    @Transactional

    public Result creatVoucherOrder(Long voucherId) {

        Long userId = UserHolder.getUser().getId();

        Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();

        if (count > 0) {

            return Result.fail("用户已经购买过了");

        }

        //5 扣减库存-

        boolean success = seckillVoucherService.update()

                .setSql("stock = stock -1 ")  //乐观锁

                .eq("voucher_id", voucherId).gt("stock", 0) //判断库存是否大于0: where id = ? and stock > 0

                .update();

        if (!success) {

            return Result.fail("库存不足");

        }

        //6 创建订单

        //6.1 订单ID

        VoucherOrder voucherOrder = new VoucherOrder();

        long orderid = RedisIdWorker.nextId("order");

        voucherOrder.setVoucherId(orderid);

        //6.2 用户ID

        voucherOrder.setUserId(userId);

        //6.3 代金券ID

        voucherOrder.setVoucherId(voucherId);

        save(voucherOrder);

        //7 返回订单id

        return Result.ok(orderid);

    }

}

原文链接:
相关文章
最新更新