lua脚本
lua脚本为了保证多条命令组合的原子性。
事务
将一组需要一起执行的命令放在multi和exec两个命令之间,multi命令表示事务开始,exec命令表示事务结束,它们之间的命令原子顺序执行。
有些应用场景需要确保key没有被其他客户端修改过才执行事务,否则不执行,redis使用watch命令来实现该功能,watch命令是一个乐观锁。
如果出现语法错误,会造成整个事务无法执行,已经执行的命令不生效。
如果运行时命令错误,redis并不支持回滚。
lua代码编写
# --- strings(字符串)
# local: 局部变量
local strings val = "world"
print(val) # world
# ---- tables(数组)
# 数组下标从1开始计算
local tables myArray = {"redis","jedis",true,88.0}
print(myArray[3])# true
local int sum=0
# for遍历计算1-100的和
for i=1,100
do
sum=sum+1
end
print(sum) # 5050
# while循环计算1-100的和
local int i=0
while i<=100
do
sum=sum+1
i=i+1
end
print(sum) # 5050
# for遍历myArray,判断数组中是否包含"jedis"
for i=1,#myArray # 在数组变量前加#号,获知数组长度
do
if myArray[i]=="jedis"
then
print("true")
break
else
--do nothing
end
# for遍历myArray索引下标和值
for index,value in ipairs(myArray) # ipairs函数
do
print(index)
print(value)
end
# 使用数组实现哈希
local tables user_1 = {age=28,name="tome"}
# str1..str2 是将两个字符串进行拼接
print("user_1 age is" .. user_1["age"])
# 使用内置函数pairs遍历user_1
for key,value in pairs(user_1)
do print(key .. value)
end
# ---function函数 以function开头,以end结尾
# 实现contact函数拼接两个字符串
function contact(str1,str2)
return str1..str2
end
# redis.call函数可以直接在lua脚本中执行redis命令
> EVAL "return redis.call('PING')" 0
PONG
“127.0.0.1:6379> eval 'return redis.call("get", KEYS[1])' 1 hello
"world”
lua原理
lua环境
- 为了在redis服务器中执行lua脚本,redis服务器中内置了一个lua环境。
- 在lua环境中载入多个函数库
- 创建全局表格redis,表格中包含了对redis进行操作的函数,比如在lua脚本中执行redis命令的redis.call
- 使用redis自制的随机函数替换lua原有的带有副作用的随机函数,多次调用随机函数效果相同
- 创建排序复制函数,可以对redis命令结果进行排序,从而消除命令的不确定性
- 创建redis.pcall的错误报告辅助函数
- 将lua环境中的全局环境进行保护,防止执行lua脚本过程中将额外的全局变量添加到lua环境
lua环境协作组件
- 伪客户端,执行redis命令必须有相应的客户端状态,redis服务器专门为lua环境创建一个伪客户端,由伪客户端处理lua脚本中包含的redis命令
- lua_scripts字典。key是lua脚本的SHA1校验和,value是对应的lua脚本。被eval命令执行过的和被script load命令载入过的lua脚本保存在lua_scripts字典中。字典可以实现script exists和脚本复制功能。
eval命令可以直接对输入的脚本进行求值,evalSHA命令可以根据脚本的SHA1校验和对脚本求值。
eval
eval [脚本内容] [key个数] [key列表] [参数列表]
127.0.0.1:6379> eval 'return "hello " ..KEYS[1] .. ARGV[1]' 1 redis world
"hello redis world"
# 脚本较长,可以使用redis-cli --eval直接执行xxx.lua脚本
> redis-cli --eval xxx.lua
如果lua脚本较长,可以使用redis-cli --eval直接执行文件
evalsha
将lua脚本加载到redis服务器,得到脚本的SHA1校验和。使用SHA1作为参数可以直接执行对应lua脚本,避免每次发送lua脚本的开销。
> redis-cli script load "$(cat lua_get.lua)"
"7413dc2440db1fea7c0a0bde841fa68eefaf149c" # SHA1码
> evalsha 7413dc2440db1fea7c0a0bde841fa68eefaf149c 1 redis world
"hello redisworld"
其他脚本命令
- SCRIPT EXISTS:根据输入的SHA1校验和,检查校验和对应的脚本是否存在于服务器
- SCRIPT FLUSH:清除服务器中所有与Lua脚本有关的信息
- SCRIPT KILL: 指示服务器停止执行未进行写入操作的超时运行的脚本,并向脚本客户端发送错误回复
- SCRIPT LOAD:在lua环境为脚本创建相对应的函数,将脚本保存到lua_scripts字典中
参考
《redis设计与实现》
《redis开发与运维》
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情