Lua脚本在redis中的使用学习

2023-11-19

Lua脚本在redis中的使用学习

0.前言

不同于之前遇到的redisTemplate的简单set、get方法,这里是使用Redis脚本执行redis操作。

DefaultRedisScript<List> script = LuaUtils.queryByVinsScript();
List<String> keys = LuaUtils.queryByVinsKeys(vins);
redisTemplate.execute(script, keys, redisArgs);

1.使用redis脚本的原因

在一些使用redis的场景中,会经常遇到并发问题。为了控制命令的执行顺序,redis提供了脚本执行功能。

Redis 保证脚本会以原子性(atomic)的方式执行: 当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。

2.案例

public static List<String> queryByVinsKeys(Set<String> vins) {
    return vins.stream().map(vin -> PREFIX_LATEST + vin).collect(Collectors.toList());
}

/**
 * @return 数据内容:DATA|DATA|....|DATA
 */
public static DefaultRedisScript<List> queryByVinsScript() {
    String luaScript = "local datas = {} ";
    luaScript += "for i = 1, #KEYS do ";
    luaScript += "  local data = redis.call('hget', KEYS[i], 'data') ";
    luaScript += "  if data ~= false then ";
    luaScript += "      table.insert(datas, data) ";
    luaScript += "  end ";
    luaScript += "end ";
    luaScript += "return datas ";
    DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
    redisScript.setScriptText(luaScript);
    redisScript.setResultType(List.class);
    return redisScript;
}

上面的两个方法,一个是获取指定脚本中的keys,一个是获取指定脚本script,这两个参数是执行redis脚本必须要传的参数。

还有一个参数redisArgs,是想传入脚本的key以外的参数,也可以参与脚本的执行,这个参数是选填。

  • keys

这里不必详述,你要查询的存储在redis中的数据对应的keys,可以看到它的结构是List,可以传递一个或者多个key

  • script

这里是要执行的脚本内容,脚本是用Lua编写的。其中每一行代码的含义如下:

-- 定义一个空表datas,用于存储查询到的数据
local datas = {}
-- 定义一个循环,循环从1开始,循环的次数是传入的keys的数量;#KEYS-获取KEYS的长度
for i = 1, #KEYS do  
	-- 循环体第一行,执行redis命令查询数据存储到变量data里,相当于命令:hget 第i个key 'data',i是循环的次数,'data'是要查询的字段名
    -- 例如我在redis中存的是hash类型的数据。其中keys有:student1、student2、student3...,每一个key对应的value是类似这样结构			{"id":1,"name":"zhangsan","age":10}的数据,那么我要获取student1、student2、student3的name,这里第一次循环执行的命令就是 hget student1 'name'
	local data = redis.call('hget', KEYS[i], 'data')   
    -- 循环体第二行,判断:如果变量data不等于false;~=-不等于
    if data ~= false then  
        -- 循环体第三行,如果上面的判断成立:把变量data存到循环体外面定义的空表datas中
        table.insert(datas, data)  
    -- 循环体第四行,结束判断。
    end 
-- 结束本次循环
end 
--返回表datas
return datas 

3.Lua语法

3-1 Lua数据类型

数据类型 描述
nil 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean 包含两个值:false和true。
number 表示双精度类型的实浮点数
string 字符串由一对双引号或单引号来表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的C数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

其中table就是上面的案例中用到的。

local的意思的局部变量,如果前面不加则默认为全局变量

-- 创建一个空的 table
local tbl1 = {}
 
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}

-- 遍历在控制台打印输出表tbl2的索引
for key, val in pairs(tbl2) do
    print("Key", key)
end
-- 执行结果
Key    1
Key    2
Key    3
Key    4

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。 Lua 里表的默认初始索引一般以 1 开始

-- table_test.lua 脚本文件
a = {}
a["key"] = "value"
key = 10
a[key] = 22
a[key] = a[key] + 11
for k, v in pairs(a) do
    print(k .. " : " .. v)
end

相当于表table的存储数据结构如下表所示,由值和索引组成,根据索引读和写值。

“value” 22 值n
索引 “key” 10 索引n
  • 注意:通过索引获取值时,常规写法是:table[i]。当索引为字符串类型时的,也可以简化为:table.i。

  • > site = {}
    > site["key"] = "www.runoob.com"
    > print(site["key"])
    www.runoob.com
    > print(site.key)
    www.runoob.com
    

3-2 Lua 变量

  • 变量在使用前,需要在代码中进行声明,即创建该变量

  • 如果不用local声明,则默认为全局变量。

  • 未声明和未赋值的变量默认值未nil,相当于不存在。

  • 删除变量的方法为:给变量赋值为nil。

-- 声明变量
a = 5               -- 全局变量
local b = 5         -- 局部变量
c,d = 1,2
-- 给变量重新赋值
a = "hello" .. "world"  -- 字符串拼接语法:str ... str
b = b + 1				-- 数字类型计算语法:num + num

-- 给多个变量赋值时,当变量的个数与值的个数不匹配时的规则
a, b, c = 0, 1
print(a,b,c)             --> 0   1   nil
 
a, b = a+1, b+1, b+2     -- value of b+2 is ignored
print(a,b)               --> 1   2
 
a, b, c = 0
print(a,b,c)             --> 0   nil   nil

3-3 Lua循环

for循环语法

-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1
-- 相当于 for(int var = exp1;i <= exp2;i + exp3)
for var=exp1,exp2,exp3 do  
    <执行体>  
end  

for循环例子

for i=1,f(x) do
    print(i)
end
 
for i=10,1,-1 do
    print(i)
end

for的三个表达式在循环开始前一次性求值,以后不再进行求值。比如上面的f(x)只会在循环开始前执行一次,其结果用在后面的循环中。

function f(x)  
    print("function")  
    return x*2  
end  
for i=1,f(5) do 
    print(i)  
end
-- 运行结果
function
1
2
3
4
5
6
7
8
9
10
  • 泛型for循环

泛型 for 循环通过一个迭代器函数来遍历所有值,类似 java 中的 foreach 语句。

Lua 编程语言中泛型 for 循环语法格式:

--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 

i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}  
for i,v in ipairs(days) do
    print(v) 
end
-- 运行结果
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua脚本在redis中的使用学习 的相关文章

  • 如果另一个键中的计数器低于零,则从集合中原子删除一个项目?

    雷迪斯2 0 3 在我的 Redis DB 中 我有一组项目 每个项目都有一个与其关联的计数器 MULTI SADD items set foo INCRBY items foo 10000 EXEC 新项目会以随机间隔添加到集合中 当用户
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • Caffeine Expiry 中如何设置多个过期标准?

    我正在使用 Caffeine v2 8 5 我想创建一个具有可变到期时间的缓存 基于 值的创建 更新以及 该值的最后一次访问 读取 无论先发生什么都应该触发该条目的删除 缓存将成为三层值解析的一部分 The key is present i
  • 确定已编译Lua的编译器版本

    我有一些已编译的 LuaQ 我需要确定用于编译它的确切版本 有什么可能的方法吗 编译的脚本在文件开头有一个标头 4 bytes signature x1bLua 1 byte version 0x51 1 byte format 1 byt
  • 尝试将 nil 与数字堆栈回溯进行比较?

    我正在通过以下链接玩 Lua https www lua org pil 4 2 html https www lua org pil 4 2 html并对某一点感到困惑 Lua 5 2 4 Copyright C 1994 2015 Lu
  • Lua中如何获取表中的最大整数?

    Lua中如何获取表中的最大整数 在Lua 5 1及更早版本中 你可以使用 math max unpack 1 2 3 4 5 这受到Lua堆栈大小的限制 在 PUC Lua 5 1 上 该值的最大值可达 ca 8000 个数字 如果堆栈空闲
  • 在 sidekiq 上配置 redis 身份验证

    我想我错过了一些东西 因为我在文档中找不到如何编写 redis 实例的用户名和密码以与 sidekiq 一起使用 有没有办法做到这一点 或者是通过 ENV 变量 Sidekiq 将无法识别的 Redis 选项直接传递给 Redis 驱动程序
  • 在lua中组合两个函数

    我刚开始学习lua 所以我的要求可能是不可能的 现在 我有一个接受函数的方法 function adjust focused window fn local win window focusedwindow local winframe w
  • 使用 FastCGI 运行 Lua 脚本

    我目前正在尝试找出使用 FastCGI 与 lighttpd 或 Nginx 一起运行 Lua 脚本的方法 我唯一能挖到的是WSAPI http keplerproject github com wsapi 开普勒计划的一部分 但我想知道是
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 安装Lua套接字库

    要么我太累了 要么我瞎了 我想学习 Lua 网络 因此我必须安装socketlib 所以我可以轻松地要求它 但我不知道我应该 要求 哪些文件 例子说 local socket require socket 但正如我所说 如果我使用 我不知道
  • 如何在Redis中从hmset()切换到hset()?

    我收到弃用警告 即 Redis hmset 已弃用 请改用 Redis hset 但是 hset 采用第三个参数 我不知道是什么name应该是 info users 10 timestamp datetime utcnow strftime
  • Lua中按字符分割字符串

    我有像这样的字符串 ABC DEF 我需要将它们分开 字符并将两个部分分别分配给一个变量 在 Ruby 中 我会这样做 a b ABC DEF split 显然Lua没有这么简单的方法 经过一番挖掘后 我找不到一种简短的方法来实现我所追求的
  • Redis Cluster 与 Pub/Sub 中的 ZeroMQ,用于水平扩展的分布式系统

    如果我要设计一个巨大的分布式系统 其吞吐量应随系统中的订阅者数量和通道数量线性扩展 哪个会更好 1 Redis集群 仅适用于Redis 3 0 alpha 如果是集群模式 您可以在一个节点上发布并在另一个完全不同的节点上订阅 消息将传播并到
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • redis - 使用哈希

    我正在使用 redis 为我的 Web 应用程序实现社交流和通知系统 我是 redis 的新手 我对哈希值及其效率有一些疑问 我读过这篇很棒的文章Instagram 帖子 http instagram engineering tumblr
  • 比较 Lua 中的日期

    我有一个带有日期表的变量 如下所示 table day number 15 year number 2015 month number 2 如何获取当前日期与上述日期之间的天数 非常感谢 您可以使用os time 将表转换为秒并获取当前时间
  • StackExchange.Redis Get 函数抛出 TimeoutException

    我在用着StackExchange Redis与 C 和StackExchangeRedisCacheClient Get函数抛出以下异常 myCacheClient Database StringGet txtKey Text myCac
  • 想要在后台不间断地运行redis-server

    我已经下载了 redis 2 6 16 tar gz 文件并安装成功 安装后我运行 src redis server 它工作正常 但我不想每次都手动运行 src redis server 而是希望 redis server 作为后台进程持续
  • 在Luasocket中,在什么条件下,即使在select告诉它可以安全读取之后,accept调用也可以阻塞?

    卢阿索基特select http w3 impa br diego software luasocket socket html select函数应该告诉何时可以在不阻塞的情况下读取套接字 它显然也可以用来告诉服务器套接字何时准备好接受新连

随机推荐

  • Git提交代码报错:remote: HTTP Basic: Access denied

    一 问题 由于账号更改或其他原因导致提交代码时报错 账号密码验证不通过 密码或者权限不对 导致 Git 操作失败 remote HTTP Basic Access denied fatal Authentication failed for
  • PCAP01介绍和STM32模拟SPI驱动

    一 芯片介绍 Pcap01是德国acam公司设计的一款革命性的电容测量芯片 该芯片 内部有DSP计算单元 可以直接将电容元件接到Pcap01芯片 然后芯片计算出容值大小 通过SPI总线将电容容值数据传送给CPU 电容测量完全数字化 二 测量
  • Hive中Inner join、Outer join、Full join中on与where的执行计划与结果区别

    背景 本文主要讨论hive 版本2 3 中 不同join方式下on条件和where条件的区别 同时关注hive中如何执行语句 比如谓词下推 就是其中一种优化技术 原表 person表 person id person name person
  • CentOS7安装MySQL8.0详细教程

    这个是我和我结合网上其他一些朋友的操作来做的 1 下载 MySQL 所需要的安装包 网址 https dev mysql com downloads mysql 2 Select Operating System 选择 Red Hat Ce
  • QT学习之四:Linux 下 Qt Creator 的一个Qt 项目全过程

    Linux 下 Qt Creator 的一个Qt项目全过程 1 启动桌面上的 Qt Creator 新建工程 HelloWorld 点击 File gt New File orProject 如下图所示 2 新建类 Hello 右键单击项目
  • Three.js中光线投射Raycaster的简单使用案例 与模型的交互,当鼠标移动到模型时出现信息框

    无用的话 本人是编程小白 想创建一个氛围好的技术交流群 喜欢技术分享 技术指导 技术交流的朋友可以进Q群 732515998 大家一起快乐编程 想发公告的就不要进来了 目录 说明 创建两个模型 基础代码 基础代码效果图如下 重点 创建光线投
  • Android webview加载网页

    webview尝试 一 在线加载网页 例百度 webview布局很简单xml如下
  • 快速椭圆检测代码调试记录

    代码环境 Windows11 vs2019 opencv3 3 1 Debugx64 一 代码注释 1 realpath PATH MAX basename 这几句是为了在Ubuntu中运行时 寻找路径用的 Ubuntu需要比较严格的路径
  • 人工智能AI工具汇总(AIGC ChatGPT时代个体崛起)

    Name Category Website Description 描述 AIGC时代 超级个体的崛起 小报童 https xiaobot net p SuperIndividual 介绍AIGC ChatGPT 使用技巧与搞钱方式 Mas
  • React学习(编程式导航)

    学习目标 提示 这里可以添加学习目标 1 编程式导航 编程式导航 提供了通过脚本代码实现页面跳转的功能 主要api函数包含在路由对象参数 history中 this props history push login 跳转到登录路径 保留访问
  • java 调用controller_java调用controller方法

    我们有一个路由StudentController 里面有一个方法count 如果要在另外一个GradeController中调用count 方法有2种方式 因为StudentController是一个class 不是接口 接口一般都是 Au
  • 用 plt 画折线图(将训练过程中的每个epoch 的准确率和损失用图的形式展示出来)

    代码 import matplotlib pyplot as plt epochs range 0 4 acc 2 1 2 3 1 4 5 loss 1 1 1 4 0 8 0 6 plt plot epochs acc color r l
  • python sklearn 梯度下降法_【机器学习】梯度下降法(Gradient descent)

    说明 以下内容为学习刘建平老师的博客所做的笔记 梯度下降 Gradient Descent 小结 www cnblogs com 因为个人比较喜欢知乎文章的编辑方式 就在这里边记笔记边学习 喜欢这个博客的朋友 可以去刘建平老师的博客foll
  • 使用google的免费GPU

    1 打开网页 输入Google colab 2 点击 修改 gt 笔记本设置 3 点击使用GPU 常用命令 print torch version print torch cuda is available
  • 1.centos7安装docker

    本文目录 1 docker 安装 1 安装步骤 2 安装是否成功校验 3 docker加速配置 4 hello world来袭 验证安装是否ok 2 卸载docker 3 卸载较旧版本docker 使用docker必备的三个官方网站 doc
  • 无线路由、AP、网桥之区别详解篇

    通过无线上网冲浪 现在已经不是新鲜的事情 随着近一两年无线 网络的飞速发展 从企业到家庭都开始在不同的领域体验着 自由上网 的乐趣 笔者接触无线网络也有一段时间了 经常在一些无线论坛逛游 无论是在现实生活还是在论坛中 总会有朋友不断的问这样
  • HyperLedger Fabric 实践错误收集

    HyperLedger Fabric 实践错误收集 在ubuntu中通过docker compose启动容器的时候报错 ERROR for cli Cannot create container for service cli Confli
  • 光模块之SR、LRM、LR、ER 、ZR对比介绍

    SFP介绍 现有的ARUBA 原来的HP 万兆模块有多种 除了MMF表示多模SMF表示单模 SR LRM LR ER等都代表什么意思 本文做个简单对比介绍 将帮助您根据您的实际需要选择合适的10G SFP 模块 Aruba 10G SFP
  • 英语软件的日志怎么写

    今天一个外企个小伙伴跑来跟我说 老板说他的程序里的英语写的太烂 让我教他怎么写日志 虽然我自己用英语写log 也还马马虎虎 但是让我系统的介绍 我也犯了难 好在 我做过自然语言处理 NLP 也做过针对计算机系统的日志的挖掘 所以我知道有个东
  • Lua脚本在redis中的使用学习

    Lua脚本在redis中的使用学习 0 前言 不同于之前遇到的redisTemplate的简单set get方法 这里是使用Redis脚本执行redis操作 DefaultRedisScript