当前位置: 首页 > news >正文

Lua脚本 快速掌握

1.Lua脚本概述

Lua是一种轻量级的编程语言,由巴西里约热内卢天主教大学开发。设计初衷是为了嵌入应用程序中,提供灵活的配置和脚本能力。Lua具有简洁的语法和强大的扩展性,使得它在多个领域得到了广泛应用。

Lua的特点包括动态类型、自动内存管理、协程、模块和包支持。它使用表(Table)这一数据结构来实现关联数组、集合等多种功能。Lua的执行速度快,且库体积小。

教程链接:Lua 教程 | 菜鸟教程 (runoob.com)

2.快速入门实操:

(1)创建lua脚本

例如在resource下创建名为unlock.lua的脚本:

if(redis.call('get',KEYS[1]) == ARGV[1]) thenreturn redis.call('del',KEYS[1])
end
return 0

说明:

  • if 是Lua的条件判断关键字。
  • redis.call 是Lua脚本中调用Redis命令的方法。在这里,它调用了Redis的 GET 命令。
  • KEYS[1] 是一个特殊变量,代表传递给Lua脚本的键名列表中的第一个键。
  • ARGV[1] 是另一个特殊变量,代表传递给Lua脚本的参数列表中的第一个参数。
  • end 标志着if语句块的结束。
  • 如果if条件不成立(即键值不匹配),则执行这个 return 语句。
  • 返回值 0 表示没有进行任何操作。

(2)编写代码

    private static final String KEY_PREFIX = "lock:";private static final String ID_PREFIX = UUID.randomUUID().toString();// 定义一个静态常量 UNLOCK_SCRIPT,类型为 DefaultRedisScript,预期返回值类型为 Longprivate static final DefaultRedisScript<Long> UNLOCK_SCRIPT;// 静态初始化块,用于初始化静态常量 UNLOCK_SCRIPTstatic{UNLOCK_SCRIPT = new DefaultRedisScript<>();// 设置 Lua 脚本的路径,这里脚本是从类路径下的资源文件 "unlock.lua" 中加载UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));// 指定脚本执行后的返回值类型为 Long.classUNLOCK_SCRIPT.setResultType(Long.class);}@Overridepublic boolean tryLock(long timeoutSec) {String threadId = ID_PREFIX + Thread.currentThread().getId();Boolean flag  = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+name,threadId,timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(flag);}@Overridepublic void unlock(){// 使用 StringRedisTemplate 执行 Lua 脚本 UNLOCK_SCRIPTstringRedisTemplate.execute(// 传递预定义的 Lua 脚本对象 UNLOCK_SCRIPTUNLOCK_SCRIPT,// 传递一个包含锁键的列表,这里锁键由前缀和锁的名称组成Collections.singletonList(KEY_PREFIX + name),// 传递一个参数,该参数是线程 ID 前缀加上当前线程的 IDID_PREFIX + Thread.currentThread().getId());}

3.了解Spring Data Redis提供的execute方法

查看源码可以知道execute方法可知

第一个参数:确定返回的类型值和脚本文件的位置

第二个参数:传递给脚本文件key的值,如果没有想传递的key值可以传递为空的Collections.emptyList()。在脚本文件中通过KEYS[序号]获取,例如KEY[1]表示第一个Key的值

之后的参数:传递给脚本文件arg的值,在脚本文件中通过ARGV[序号]获取,例如AVG[1]表示第一个arg的值

 4.更复杂的lua脚本示例代码

这里只写了lua脚本,还需要在使用Spring Data Redis提供的 execute方法才能运行,

-- 优惠卷ID,通过ARGV参数传递,ARGV[1]是第一个参数
local voucherId  = ARGV[1]-- 用户ID,通过ARGV参数传递,ARGV[2]是第二个参数
local userId = ARGV[2]-- 订单ID,通过ARGV参数传递,ARGV[3]是第三个参数
local orderId = ARGV[3]-- 库存Key,拼接字符串构建库存的Redis键名
local stockKey = 'seckill:stock:' .. voucherId-- 订单Key,拼接字符串构建订单的Redis键名
local orderKey = 'seckill:order:' .. voucherId-- 脚本业务逻辑开始-- 检查库存是否充足,使用get命令获取库存数量,如果库存小于等于0则返回1
if(tonumber(redis.call('get',stockKey)) <=0 ) then-- 库存不足,返回1,这里1通常表示库存不足的错误码return 1
end-- 判断用户是否已经下过单,使用sismember命令检查订单集合中是否包含该用户ID
-- 如果用户已存在订单集合中,返回2
if(tonumber(redis.call('sismember',orderKey,userId)) == 1 ) then-- 用户已下单,返回2,这里2通常表示用户重复下单的错误码return 2
end-- 如果库存充足且用户未下单,则减少库存数量,使用incrby命令对库存进行减一操作
redis.call('incrby',stockKey,-1)-- 将用户ID添加到订单集合中,记录用户已下单,使用sadd命令添加集合元素
redis.call('sadd',orderKey,userId)-- 将订单信息发送到消息队列中,使用xadd命令向stream.orders消息队列添加一条消息
-- '*': 表示自动生成消息ID
-- 'userId',userId: 消息字段名为userId,值为脚本传入的userId
-- 'voucherId',voucherId: 消息字段名为voucherId,值为脚本传入的voucherId
-- 'id',orderId: 消息字段名为id,值为脚本传入的orderId
-- 发送消息到队列中 XADD stream.orders * k1 v1 k2 v2
--(下面的key值请参考实体类所定义的,因为这个lua脚本是创建订单信息,所以oderId对应实体的id)
redis.call('xadd','stream.orders','*','userId',userId,'voucherId',voucherId,'id',orderId)-- 如果脚本执行至此,表示操作成功,返回0
return 0

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 华为设备的两种配置生效模式
  • 深度学习 —— 个人学习笔记20(转置卷积、全卷积网络)
  • 【大数据】6:MapReduce YARN 初体验
  • DAMA学习笔记(十五)-数据管理组织与角色期望
  • 模拟三层--控制层、业务层和数据访问层
  • 抓包分析排查利器TCPdump
  • Qt读写sysfs
  • 8月13日学习笔记 LVS
  • 代码随想录算法训练营day42|动态规划part09
  • 【中等】 猿人学web第一届 第5题 js混淆-乱码增强
  • HAProxy原理及实例
  • 51单片机学习记录-数码管操作
  • Unity 流光shader的思路
  • 开源模型应用落地-LangChain高阶-记忆组件-RedisChatMessageHistory正确使用(八)
  • java注解(实现原理及自定义注解)
  • hexo+github搭建个人博客
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • Android交互
  • 百度小程序遇到的问题
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 收藏好这篇,别再只说“数据劫持”了
  • 线性表及其算法(java实现)
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • nb
  • Java数据解析之JSON
  • 积累各种好的链接
  • # windows 运行框输入mrt提示错误:Windows 找不到文件‘mrt‘。请确定文件名是否正确后,再试一次
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (回溯) LeetCode 78. 子集
  • (简单) HDU 2612 Find a way,BFS。
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (十六)一篇文章学会Java的常用API
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (算法)Game
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转载)OpenStack Hacker养成指南
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET CLR基本术语
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .net Signalr 使用笔记
  • .NET连接数据库方式
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • @angular/cli项目构建--http(2)
  • @Builder用法
  • @for /l %i in (1,1,10) do md %i 批处理自动建立目录
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [000-01-018].第3节:Linux环境下ElasticSearch环境搭建
  • [12] 使用 CUDA 加速排序算法