通过redis的脚本lua实现抢红包功能的方法
发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,这篇文章主要讲解了通过redis的脚本lua实现抢红包功能的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。redis 脚本介绍Redis从2.6版本开始,通过内嵌支持
千家信息网最后更新 2025年11月12日通过redis的脚本lua实现抢红包功能的方法
这篇文章主要讲解了通过redis的脚本lua实现抢红包功能的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。
redis 脚本介绍
Redis从2.6版本开始,通过内嵌支持Lua环境
好处
- 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络延迟
- 原子操作。redis将整个脚本当作一个整体去执行,中间不会被其他命令插入,无需担心脚本执行过程中会出现竞态条件
- 复用。客户端发送的脚本会永久保存在redis中,可以复用这一脚本
数据库表设计
简单两张表,一个红包表,一个红包领取记录表
CREATE TABLE `t_red_envelope` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `amount` decimal(10,2) DEFAULT NULL COMMENT '金额', `num` int(11) DEFAULT NULL COMMENT '数量(分割成几分)', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='红包'CREATE TABLE `t_red_envelope_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', `reward` decimal(10,2) DEFAULT NULL COMMENT '领取到奖励', `red_envelope_id` bigint(20) DEFAULT NULL COMMENT '红包id', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COMMENT='红包领取记录'
代码编写
首先,生成一个红包,将其分成指定数量的随机小红包,以list结构(envelope:redEnvelopeId:红包id作为key)存储在reids中(以便抢红包弹出数据)
public Long divideRedEnvelope(int amount, int num) { /** * 每个人至少分到一分钱,如果有2000分,6人,随机得到五个小于1994(2000-6)的数 * 比如 a1=4,a2=120,a3=324,a4=500,a5=700(随机拿到的五个数进行排序),那么红包钱分别为: a1+1,a2-a1+1,a3-a2+1,a4-a3+1,a5-a4+1,1994-a5+1(总和刚好为2000) */ RedEnvelope redEnvelope = new RedEnvelope(); redEnvelope.setAmount(new BigDecimal(amount)); redEnvelope.setNum(num); redEnvelope.setCreateTime(new Date()); redEnvelope.setUpdateTime(new Date()); redEnvelopeDao.insert(redEnvelope); /** * 拿来随机分的,按分来算 */ int totalAmount = amount * 100 - num; /** * 随机数 */ int[] randomNum = new int[num - 1]; /** * 红包金额 */ int[] redEnvelopeAmount = new int[num]; for (int i = 0; i < num - 1; i++) { int rand = new Random().nextInt(totalAmount); randomNum[i] = rand; } Arrays.sort(randomNum); /** * 条件语句分别分配的第一个、最后一个、中间的红包 */ for (int i = 0; i < num; i++) { if (i == 0) { redEnvelopeAmount[i] = randomNum[i] + 1; } else if (i == num - 1) { redEnvelopeAmount[i] = totalAmount - randomNum[i - 1] + 1; } else { redEnvelopeAmount[i] = randomNum[i] - randomNum[i - 1] + 1; } } /** * 产生的小红包key,以list存储在reids中 */ String key = "envelope:redEnvelopeId:" + redEnvelope.getId(); Boolean flag = stringRedisTemplate.hasKey(key); if (!flag) { for (Integer i : redEnvelopeAmount) { stringRedisTemplate.opsForList().leftPush(key, i + ""); } } return redEnvelope.getId(); }抢红包时,根据用户userId和红包id,生成KEYS[1]、KEYS[2]、KEYS[3] (存储小红包的key、领取红包记录的key、用户userId的key)传入脚本中。
1、先判断该用户是否抢过红包,有则返回-1,没有则从红包列表取出一个小红包
2、步骤1的小红包如果为空,则表明红包已经没抢光,返回 -2
3、否则返回取出的小红包金额
public String grabRedEnvelope(Long userId, Long redEnvelopeId) { DefaultRedisScript redisScript = new DefaultRedisScript<>(); redisScript.setResultType(String.class); redisScript.setScriptText(LuaScript.redLua); List keyList = new ArrayList(); /** * 产生的小红包key */ keyList.add("envelope:redEnvelopeId:" + redEnvelopeId); /** * 红包领取记录key */ keyList.add("envelope:record:" + redEnvelopeId); keyList.add("" + userId); keyList.add(String.valueOf(userId)); /** * -1 已经抢到红包 -2 红包已经完了 ,其余是抢到红包并返回红包余额 */ String result = stringRedisTemplate.execute(redisScript, keyList); return result; } 实现抢红包的Lua脚本
public class LuaScript { /** * -1 已经抢到红包 -2 红包被抢光 re 红包金额 ,keys[1]、keys[2]、keys[3]分别为存储小红包的key、红包领取记录key、用户id */ public static String redLua = "if redis.call('hexists',KEYS[2],KEYS[3]) ~=0 then \n" + " return '-1';\n" + " else \n" + "local re=redis.call('rpop',KEYS[1]);\n" + "if re then\n" + "redis.call('hset',KEYS[2],KEYS[3],1);\n" + "return re;\n" + "else\n" + "return '-2';\n" + "end\n" + "end";}测试
首先通过接口分配红包生成一个100块、份额为10份的红包,并将其mysql数据库和redis
通过jmeter进行压测抢红包
结果
看完上述内容,是不是对通过redis的脚本lua实现抢红包功能的方法有进一步的了解,如果还想学习更多内容,欢迎关注行业资讯频道。
红包
脚本
用户
时间
存储
内容
数据
金额
生成
功能
方法
数据库
数量
条件
网络
别为
分配
复用
学习
更新
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
上海开展网络安全
监控搜索服务器
jsp 数据库编程
如何知道自己服务器的80端口
泉州户外直播软件开发
三级网络技术2020
自助缴费终端软件开发
英雄联盟服务器查询
北海软件开发制作
课件数据库原理
成都网络安全培训机构哪个好
大学网络技术部申请书
网络技术的应用有
不同的方法关闭数据库
媒体数据库排名
阳光网络安全插画
安卓系统软件开发收费
嘉铭软件开发公司
人工神经网络技术例题
传输网络安全论文
单验方数据库
北京软件开发人员 待遇
东莞自主可控软件开发销售厂
解说我的世界多人服务器
数据库 好友关系
excel数据库统计
服务器iops计算
吉林网络安全大会
光猫 时间服务器设置方法
河南网络软件开发定制收费