废话不多说,直接上代码

 //平分红包public static final Integer normalPacket = 1;//拼手气红包public static final Integer luckyPacket = 2;//默认最小红包金额public static final BigDecimal minAmount = new BigDecimal(0.1);@Override@Transactionalpublic BigDecimal receiveRedPacket(ReceiveRedPacketEntity rrp) {//是否已经领过if (redPacketUserMapper.checkUserHadReceived(rrp.getRedPacketId(), rrp.getUserid())) {//您已领取过,不可重复领取throw new RuntimeException(ExceptionEnum.Already_Have_Received);}RedPacket rp = null;Boolean flag = false; //执行成功flagint k = 0; //一次请求最多执行3次BigDecimal money = null;while (!flag && k < 3) {//红包信息select …… for update 行锁rp = redPacketMapper.checkRedPacketInfo(rrp.getRedPacketId());if (rp == null) {//数据跑丢了,啥也没找到~throw new RuntimeException(ExceptionEnum.Nothing_Found);}//红包剩余判断if (rp.getRestCount() <= 0) {//手慢啦,红包被抢完啦throw new RuntimeException(ExceptionEnum.Red_Packet_Was_Robbed);}//计算金额if (rp.getType().equals(normalPacket)) {//普通红包//初始总额除以初始总数,为红包均分金额money = rp.getOriginalAmount().divide(BigDecimal.valueOf(rp.getStartCount()));} else if (rp.getType().equals(luckyPacket)) {//拼手气红包//算出金额,当前总余额,总剩余数,小数点后一位,最小金额值money = randomHandOutAlgorithm(rp.getSurplusAmount(), rp.getRestCount(), 1, minAmount);} else {log.error("领取红包,红包的类型超出定义范围:" + rp);//未知异常throw new RuntimeException(ExceptionEnum.Missing_Error);}//计算 覆写的 红包余额BigDecimal over = rp.getSurplusAmount().subtract(money);//插入领取记录int i = redPacketUserMapper.insertRecord(rrp.getUserid(), rp.getId(), money);//更新红包,将查出来的值作为匹配条件,影响行返回0 表明红包被其他人先领一步,循环再执行,最多三次//(发放数量,覆写余额,旧值匹配)int j = redPacketMapper.updateRedPacket(1, over, rp);if (i > 0 && j > 0) {flag = true;log.info("用户:" + rrp.getUserid() + "领取红包:" + rrp.getRedPacketId() + ",金额:" + money);} else {k++;try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}}if (!flag) {//队伍拥挤,网络繁忙,请重试throw new RuntimeException(ExceptionEnum.Busy_NetWork);}return money;}

ReceiveRedPacketEntity 是接参的VO对象,ExceptionEnum是自己定义的枚举异常
拼手气算法:

/*** 随机红包金额算法** @param surplusAmount 总金额* @param restCount     总剩余个数* @param scale         小数点位* @param minAmount     最小值* @return*/public static BigDecimal randomHandOutAlgorithm(BigDecimal surplusAmount, Integer restCount, Integer scale, BigDecimal minAmount) {//剩余红包金额BigDecimal remainAmount = surplusAmount.setScale(scale, BigDecimal.ROUND_DOWN);BigDecimal amount;//剩余红包个数if (restCount > 1) {//前n-1个红包的金额,用随机算法BigDecimal random = BigDecimal.valueOf(Math.random());BigDecimal halfRemainSize = BigDecimal.valueOf(restCount).divide(new BigDecimal(2), BigDecimal.ROUND_UP);//计算单次红包的最大值,该算法也是微信的红包算法,可以保证抢红包的期望收益应与先后顺序无关,但后抢红包的方差更大,因此手气最佳更可能在后抢的人中诞生BigDecimal max1 = remainAmount.divide(halfRemainSize, BigDecimal.ROUND_DOWN);//同时,最大值需要保证,减去该红包后,剩下的红包足以满足剩余人数的最小金额BigDecimal minRemainAmount = minAmount.multiply(BigDecimal.valueOf(restCount - 1)).setScale(scale, BigDecimal.ROUND_DOWN);BigDecimal max2 = remainAmount.subtract(minRemainAmount);//最终,单次红包的最大值等于两个最大值中较小的一个BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;amount = random.multiply(max).setScale(scale, BigDecimal.ROUND_DOWN);//每个红包的数额不能小于预设的最小金额if (amount.compareTo(minAmount) < 0) {amount = minAmount;}} else {//最后一个红包,金额等于剩余金额amount = remainAmount;}return amount;}

红包条目表

CREATE TABLE `red_packet` (`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',`create_date` datetime NOT NULL COMMENT '创建时间',`modify_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '创建人',`name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '红包名',`type` int(2) NOT NULL COMMENT '红包类型 1 普通发放 2拼手气红包,影响金额的分配方式,1为平均分,2为随机分',`original_amount` decimal(10,2) NOT NULL COMMENT '初始总额',`surplus_amount` decimal(10,2) DEFAULT NULL COMMENT '剩余余额',`start_count` int(10) NOT NULL COMMENT '初始总数',`rest_count` int(10) NOT NULL DEFAULT '0' COMMENT '剩余数量',`start_date` datetime NOT NULL COMMENT '开始使用时间',`end_date` datetime NOT NULL COMMENT '结束使用时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='红包条目';

用户红包记录表

CREATE TABLE `red_packet_user` (`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',`red_packet_id` int(10) NOT NULL COMMENT '红包id,关联red_packet表',`userid` varchar(50) NOT NULL COMMENT '用户',`collect_money` decimal(10,2) DEFAULT NULL COMMENT '领取到的金额',`is_used` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已使用',`collect_date` datetime NOT NULL COMMENT '领取时间',`use_date` datetime DEFAULT NULL COMMENT '使用时间',`order_number` varchar(25) DEFAULT NULL COMMENT '使用该红包的订单号',PRIMARY KEY (`id`),UNIQUE KEY `red_packet_id` (`red_packet_id`,`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='用户红包记录表';

JAVA 拼手气红包 领取算法 记录相关推荐

  1. java 红包算法_JAVA实现拼手气红包算法

    实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...

  2. 二倍均值随机算法之抢拼手气红包场景应用

    拼手气类的游戏,更能激发用户购物和社交的趣味性,以及游戏竞争心理,拼手气类的活动甚至可以影响人们消费心理. 拼手气红包就是最简单的例子,哪怕你手气红包只有0.01元,在众多竞争者中脱颖而出,抢到的那一 ...

  3. 拼手气红包算法_二倍均值法

    使用二倍均值法进行的拼手气红包算法 假设M为总金额,N为抢红包人数,那么根据二倍均值法,每次抢到的金额 = 随机区间 (0, M / N X 2) 这个公式可以确保每个人获取的金额的平均值是相等的,不 ...

  4. 拼手气红包java_JAVA实现拼手气红包算法

    实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...

  5. 微信拼手气红包算法(二倍平均值法)实现示范代码

    二倍平均值法 优势在于不需要先把每个人得多少算出来,只有拆红包的时候才会算出这个人得多少,减少实时算力 同时保证了每个人拼手气得到的平均值相同 设有10个人,红包总额100元. 100/10X2 = ...

  6. java微信红包_Java模拟微信发红包(普通红包、拼手气红包)

    假设红包总额M元,分给N个人. 满足条件: 如果是普通红包,每个人获得的金额都一样: 如果是拼手气红包,则有所区别,但不能金额过于离谱,比如第一个获得的太多,以至于后来的人都几乎没得分. 注意点: 1 ...

  7. 拼手气红包java_拼手气红包-基于继承实现(Java萌新篇)

    拼手气红包-基于继承实现(Java萌新篇) 拼手气红包-基于继承实现(Java萌新篇) 题目: 群主发拼手气红包,n名群员收红包: 实现群主随机发送n份总金额数目一定的红包,群员收到红包,然后输出提示 ...

  8. [java] 模仿拼多多红包递减算法

    [java]模仿拼多多红包递减算法 该说不唠,直接上代码.可直接复制使用 package com.yuezhi.util;import java.math.BigDecimal;/*** @Proje ...

  9. 解析拼手气红包金额划分算法

    文章目录 问题抽象 问题简化 思路一 思路二 思路三 结束语 "叮咚",微信提示音响起,打开手机发现"相亲相爱一家人"的群里收到一个红包,天不负我,这一次终于抢 ...

最新文章

  1. 第二讲 html5 框架+Crosswalk 打包 app 以及 Angularjs 基础
  2. mysql 分表的3种方法
  3. Unity3D脚本中文系列教程(七)
  4. pandas删除某列有空值的行_Python-零基础学习Pandas知识点整理(2)
  5. Linux配置IP常用命令
  6. Linux内核笔记--内存管理之用户态进程内存分配
  7. java把控件跑挂了_Java代码动态修改 ConstraintLayout 内控件布局的辅助类
  8. Perl中的替换(七)
  9. mysql架构 三级主从同步_MySQL 主从同步架构中你不知道的“坑”
  10. 1、数列求值 - 2019年第十届蓝桥杯大赛软件类省赛
  11. ijkplayer框架详解
  12. hbase java 建表_Java在HBase数据库创建表
  13. 手把手教你微信第三方平台开发
  14. Attention UNet
  15. python实现触摸精灵功能_触摸精灵实现找图功能
  16. gazebo可以另存为world
  17. LearnOpenGL学习笔记—入门03:Hello Triangle
  18. 记云服务器中挖矿病毒与防范
  19. 全加器高进位和低进位的理解
  20. 今天股票分化好严重,一些大盘股奔涨停,一些小盘股奔跌停

热门文章

  1. 自动安装Windows2000系统
  2. 这一次,北京上海被群殴了!!
  3. 工程学导论之职业道德
  4. 人工智能软件表现抢眼,几乎准确预测了奥密克戎病毒的复杂结构
  5. 二分法查找 (长沙戴维营教育)
  6. Java的内部类详解(成员内部类、静态内部类、局部内部类、匿名内部类)
  7. python股票行情查询
  8. 雅虎正式成立 | 历史上的今天
  9. 《洛克菲勒留给儿子的38封信》 第二封:运气靠策划
  10. 聊天机器人ChatGPT在医疗领域的应用场景