哈尔滨住房和城乡建设局网站,网站建设合同是否属于技术服务合同,国企公司网站制作,WordPress评论加签到抢红包大致可以分为2步#xff1a;1 发红包 #xff1b;2 抢红包
发红包流程 为了突出红包设计主题#xff0c;以下设计会忽略支付流程、24H过期退款剩余金额、用户领取红包余额到账等业务#xff0c;则简化后的相关表设计如下#xff1a;
CREATE TABLE red_record (id…抢红包大致可以分为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)
) ENGINEInnoDB AUTO_INCREMENT16 DEFAULT CHARSETutf8 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)
) ENGINEInnoDB AUTO_INCREMENT118 DEFAULT CHARSETutf8 COMMENT抢红包记录;红包算法选取二倍均值算法保证无论用户是先抢还是后抢都保证抢到金额的概率一致。 二倍均值算法逻辑实现图 算法代码实现
/*** 二倍均值法计算红包金额* param totalAmount 总金额 单位分* param peopleNum 总人数* return*/public static ListInteger divideRedPackage(Integer totalAmount,Integer peopleNum) {ListInteger 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);//计算发红包明细金额ListInteger 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;}