Redis实现抢红包功能

需求分析

1、有一个总的大红包拆分成多个小红包,

2、一个人只能抢一次

3、红包过期 退回

4、 计时一个大红包抢完耗时多少

拆红包算法

要求

  1.   所有人抢到金额之和等于红包金额,不能超过,也不能少于。
  2. 每个人至少抢到一分钱。
  3. 保证所有人抢到金额的几率相等。

解决方案

二倍均值法
剩余红包金额为M,剩余人数为N,那么有如下公式:
 
每次抢到的金额 = 随机区间 (0, (剩余红包金额M ÷ 剩余人数N ) X 2)

发红包过程

不需要加锁,使用二倍均值法分配红包金额,lpush到redis的list中,并设置过期时间为1天

抢红包过程

首先要判断你有没有抢过,如果抢过,就显示抢的金额,

      没有抢过 rpop出去一个红包,如果redis返回null 表示抢完了,返回已抢完

      rpop出一个红包,不为null,表示抢到了,对用户抢到的红包,放入hash,作记录防止用户多次抢一个红包,然后提示用户抢到了多少钱,并进一步扣款。

解决方案

    用redist的hash,来存储用户抢过哪一个红包。

    抢红包,直接使用list的pop操作,过程不需要加锁,因为redis的工作线程是单线程的。

具体代码编写

// 发红包
@RequestMapping("/send")
    public String sendRedPackage(int totalMoney,int redPackageNumber)
    {
        //1 拆红包,总金额拆分成多少个红包,每个小红包里面包多少钱
        Integer[] splitRedPackages = splitRedPackage(totalMoney, redPackageNumber);
        //2 红包的全局ID
        String key = UUID.fastUUID().toString();
        //3 采用list存储红包并设置过期时间,红包主有且仅有一个,不用加锁控制
        redisTemplate.opsForList().leftPushAll(key,splitRedPackages);
        redisTemplate.expire(key,1, TimeUnit.DAYS);
        return key+"\t"+"\t"+ Ints.asList(Arrays.stream(splitRedPackages).mapToInt(Integer::valueOf).toArray());
    }


//抢红包流程
 @RequestMapping("/rob")
    public String rodRedPackage(String redPackageKey,String userId)
    {
        //1 验证某个用户是否抢过红包
        Object redPackage = redisTemplate.opsForHash().get(redPackageKey, userId);
        //2 没有抢过就开抢
        if (redPackage == null) {
            // 2.1 从list里面出队一个红包,抢到了一个
            Object partRedPackage = redisTemplate.opsForList().leftPop(RED_PACKAGE_KEY + redPackageKey);
            if (partRedPackage != null) {
                //2.2 抢到手后,记录进去hash表示谁抢到了多少钱的某一个红包
                redisTemplate.opsForHash().put(RED_PACKAGE_CONSUME_KEY + redPackageKey,userId,partRedPackage);
                System.out.println("用户: "+userId+"\t 抢到多少钱红包: "+partRedPackage);
                //抢到红包的用户账户金额增加
                return String.valueOf(partRedPackage);
            }
            //抢完
            return "红包抢完了";
        }
        //3 某个用户抢过
        return "message: "+"\t"+userId+" 用户你抢到的金额";
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值