通过redis的脚本lua实现抢红包功能的方法
发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,这篇文章主要讲解了通过redis的脚本lua实现抢红包功能的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。redis 脚本介绍Redis从2.6版本开始,通过内嵌支持
千家信息网最后更新 2025年01月24日通过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) { DefaultRedisScriptredisScript = 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安全错误
数据库的锁怎样保障安全
win10邮箱服务器设置
软件开发客服总结报告怎么写
网络安全安全隐患通报
基础软件开发最牛的上市公司
关于网络安全手抄报装饰
国内网络安全公司 360
关于网络安全知识的题
网络安全是什么职称
瑞庭网络技术有限公司烟台
馆陶网络安全和信息化委员会
数据库2008wmi失败
excel表查找空格数据库
网络安全基础 试卷
互联网科技教育企业
数据库技术在实践中应用领域
软件开发应准备些什么
oracle是数据库技术吗
数据库all方法
黄埔正规网络安全服务
zodb数据库
网络技术中心部门职能说明说
网络安全技术与应用 期刊
安全教育课网络安全
php数据库的分析与设计
爱看美剧软件开发
ceph上跑数据库
现代战舰一直在从服务器同步数据
数据库技术在实践中应用领域
使用adt连接数据库
松阳汇鼎互联网有限科技