抽奖案例一:按设置的概率实时抽奖-库存扣减(后台管理配置)

上次讲了保证概率的,这次我们加上库存。顺便再加一个活动。

场景:

用户参加某个活动,完成活动后获得抽奖资格,可实时抽奖,根据实际库存情况返回中奖结果。

表结构参考

拼拼凑凑几个表:

  • 活动表
  • 活动详情表
  • 奖池表
  • 奖品表
    在这里插入图片描述
    以上几个表之间都两两关联,又零零散散几个表
  • 用户获奖资格记录
  • 用户抽奖记录
  • 用户活动记录

在这里插入图片描述
具体的表结构?没有的哈 ,自己的作业自己做
在这里插入图片描述

奖品配置步骤

1.配置奖池

在这里插入图片描述

2.配置奖品信息,关联到奖池

在这里插入图片描述

用户抽奖步骤

1.完成任务获得抽奖资格

在这里插入图片描述

2.按配置的概率初步得到中奖结果

这一步怎么实现在上一篇提过了
(幸运的是 三位用户在这个流程中都中奖了,不幸的事儿还在后头(* ̄︶ ̄)
在这里插入图片描述

3.中奖用户扣减对应库存

现在我们可以看到,场上选手2 和选手3来到了赛点,究竟这个1元红包会花落谁家呢,请各位观众拭目以待!
战况直播:
用户为了争抢锁,大打出手!战况非常激烈

在这里插入图片描述

最终用户2获得了粉锁的欢心,让我们来恭喜这个B 这位用户

在这里插入图片描述

那么这个用户3怎么处理呢?

在这里插入图片描述

这个就看我们具体的需求了,你可以让他免为其难收下其他奖品(比如汤臣一品),或者狠心一点,把他算作未中奖(男人嘛,区区汤臣一品有什么是吧?)

可以看到为了保证在高并发的时候,超卖的情况,我们使用了锁。具体怎么用,来,进来,我告诉你

//中奖后查找对应的奖品信息
Prize priz = prizes.stream().filter(prize -> resultPrizeId.equals(prize.getId())).findFirst().get();
           //扣减库存
            ValueOperations vlo = redisTemplate.opsForValue();
            Boolean absent = vlo.setIfAbsent("LOCK_PRIZE_" + resultPrizeId, 1);
            try {
                if (absent) {
                    //TODO  抢占锁失败,扣减抽奖次数,记录用户未中奖信息
                   // log.info("当前锁被占用 LOCK_PRIZE_" + resultPrizeId);
                    return "锁被占用";
                } else {
                    //TODO 减少库存
                    //TODO  成功扣减库存后,变更用户抽奖次数,记录用户中奖信息
                    //TODO  如果库存为0,则返回未中奖
                    return prizeDto.getName();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                redisTemplate.delete("LOCK_PRIZE_" + resultPrizeId);
               // log.info("释放锁 LOCK_PRIZE_" + resultPrizeId);
            }

            }

随便创建几个用户和线程,模拟一下场景

public String result(@PathVariable String id, @RequestParam("times") int times)  {
Map<String, String> map = new HashMap<>();

        Runnable drawTask = () -> {
            String draw = null;
            Random random = new Random();
            int i = random.nextInt();
            draw = lotteryService.draw(id, String.valueOf(i));
            map.put(String.valueOf(i), draw);
        };

        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < times; i++) {
            Thread thread = new Thread(drawTask);
            threads.add(thread);
        }

        threads.stream().forEach(thread -> thread.start());
        threads.stream().forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                log.error(e.getMessage());
            }
        });
        //统计中奖情况
        Map<String, Long> collect = map.values().stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        collect.forEach((value,count)-> System.out.println(count+"人中:"+value));
        return JSON.toJSONString(collect);
        }

浅试一下

在这里插入图片描述
这个并发比较严重,所以看到锁经常被占用,其实我这个实际业务中 不太会同时有这么多用户抽奖。

再浅试一下

每个线程加入的时候都sleep100ms,得到
在这里插入图片描述
以上、
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值