抢红包设计

编程入门 行业动态 更新时间:2024-10-22 17:34:08

<a href=https://www.elefans.com/category/jswz/34/1696163.html style=抢红包设计"/>

抢红包设计

抢红包大致可以分为2步:1 发红包 ;2 抢红包

发红包流程

为了突出红包设计主题,以下设计会忽略支付流程、24H过期退款剩余金额、用户领取红包余额到账等业务,则简化后的相关表设计如下:

CREATE TABLE `red_record` (`id` bigint NOT NULL AUTO_INCREMENT,`user_id` bigint NOT NULL COMMENT '用户id',`total` int(11) NOT NULL COMMENT '人数',`amount` int(11) NOT NULL COMMENT '总金额(单位为分)',`status` tinyint(4) DEFAULT '1' COMMENT '状态:1 已发送,2 已抢完',`create_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='发红包记录';
// 忽略 支付流程 和 24H过期退还剩余金额CREATE TABLE `red_rob_record` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULLL COMMENT '用户ID',`red_record_id` int(11)  COMMENT '红包ID',`amount` int(11) NOT NULL COMMENT '红包金额(单位为分)',`rob_time` datetime DEFAULT NULL COMMENT '时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=118 DEFAULT CHARSET=utf8 COMMENT='抢红包记录';

红包算法选取二倍均值算法,保证无论用户是先抢还是后抢都保证抢到金额的概率一致。
二倍均值算法逻辑实现图:

算法代码实现:

/*** 二倍均值法计算红包金额* @param totalAmount 总金额 (单位分)* @param peopleNum 总人数* @return*/public static List<Integer> divideRedPackage(Integer totalAmount,Integer peopleNum) {List<Integer> list = new ArrayList<>();//金额和人数都必须大于0if (totalAmount > 0 && peopleNum > 0) {//重置入参Integer restAmount = totalAmount;Integer restNum = peopleNum;//计算红包while (restNum - 1 > 0) {//计算红包金额  高效随机数 随机范围 左闭右开 [1,restAmount / restNum * 2)//随机数使用高效的ThreadLocalRandomint amount = ThreadLocalRandom.current().nextInt(restAmount / restNum * 2 - 1) + 1;//金额减少 人数减一restAmount -= amount;restNum--;list.add(amount);}//最后一个人的红包list.add(restAmount);}return list;}

发红包代码实现:

/*** 发红包* @param totalAmount 总金额 (单位分)* @param peopleNum 总人数* @param userId 用户id* @return*/public void sendRedPackage(Integer totalAmount,Integer peopleNum,Long userId) {//金额和人数必须要大于0//持久化发红包信息RedRecordDO redRecordDO = new RedRecordDO();redRecordDO.setUserId(userId);redRecordDO.setAmount(totalAmount);redRecordDO.setTotal(peopleNum);//忽略支付流程 默认已支付redRecordDO.setStatus(1);redRecordService.save(redRecordDO);//计算发红包明细金额List<Integer> list = RedPackageUtil.divideRedPackage(totalAmount,peopleNum);//生成redis的key String key = "m:r:"+redId;//存储到redis中redisService.getListOps().rightPushAll(key,list);}

抢红包流程
抢红包直接使用redis作为数据源码,利用redis高吞吐量的特性,在发红包阶段先用红包算法将其拆分,存储到redis中的list类型中。
主要利用redis的list数据类型的lpop原子操作(移除并获取列表第一个元素)
可以在redis客户端上简单看一下 list的lpop操作:

具体代码实现如下:

    /*** 抢红包* @param redId 红包id* @param userId 领取红包的用户id* @return null 表示红包已抢完*/public Integer robRedPackage(Long redId,Long userId){//redis key ,key建议缩写 m表示系统缩写 r 表示红包缩写String key = "m:r:"+redId;//先判断key是否存在if(redisService.exists(key)){//直接弹出list中的元素 lpop是原子性 ,且弹出list所有元素后会删除这个keyInteger amount = (Integer)redisService.getListOps().leftPop(key);//元素不为空,exists不是原子性指令,则 amount可能为null if(Objects.nonNull(amount)){//元素不为空则表示抢红包成功,异步更新红包流水redRobRecordService.robRecord(redId,userId,amount);}return amount;}//直接返回红包已被抢光return null;}

更多推荐

抢红包设计

本文发布于:2024-02-06 23:39:26,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1751465.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:抢红包

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!