Lua脚本
1.简介与用法
简介
Lua语言是在1993年由巴西一个大学研究小组发明,其设计目标是作为嵌入式程序移植到其他应用程序,它是由C语言实现的,虽然简单小巧但是功能强大,所以许多应用都选用它作为脚本语言,尤其是在游戏领域,例如大名鼎鼎的暴雪公司将Lua语言引入到“魔兽世界”这款游戏中,Rovio公司将Lua语言作为“愤怒的小鸟”这款火爆游戏的关卡升级引擎,Web服务器Nginx将Lua语言作为扩展,增强自身功能。Redis将Lua作为脚本语言可帮助开发者定制自己的Redis命令,在这之前,必须修改源码。
用法
数据结构及其处理逻辑
Lua语言提供了如下几种数据类型:booleans(布尔)、numbers(数值)、strings(字符串)、tables(表格),和许多高级语言相比相对简单。下面将结合例子对Lua的基本数据类型和逻辑处理进行说明。
(1).字符串
-- 代码示例
local strings val = "hello"
print(val)
--执行结果:hello
print("world")
--执行结果:world
其中local代表val变量是一个局部变量,如果没有local修饰则代表是一个全局变量。
(2).数组
在Lua中,如果要使用类似于数组的功能,可以使用tables类型,下面代码使用定义了一个tables类型的变量myArrays,但和大多数编程语言不同的是,在Lua中的数组下表从1开始计算。
-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
print(myArrays[1])
print(myArrays[2])
print(myArrays[3])
print(myArrays[4])
--执行结果
-- hello
-- world
-- true
-- 88.0
如果想遍历数据可以使用for或者while
for
下面代码会计算1到100的和,关键字for以end作为结束符。
-- 代码示例
local int sum = 0
for i = 1, 100
do
sum = sum + i
end
print(sum)
--执行结果 5050
如果要遍历数组,则首先需要知道数组的长度,只需要在变量前加一个#号即可
-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
for i=1,#myArrays
do
print(myArrays[i])
end
--执行结果
-- hello
-- world
-- true
-- 88.0
除此之外Lua还提供了内置函数ipairs,使用 for index, value in ipairs(tables)可以遍历出所有的索引下标和值。
-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
for index, value in ipairs(myArrays)
do
print(index)
print(value)
end
--执行结果
-- 1
-- hello
-- 2
-- world
-- 3
-- true
-- 4
-- 88.0
while
下面这段代码同样会计算1到100的和。只不过使用的是while循环,while循环同样以end为结束标记。
-- 代码示例
local int sum = 0
local int i = 1
while i <= 100
do
sum = sum + i
i = i + 1
end
print(sum)
--执行结果 5050
if else
要确定数组中存不存在world,有则打印true,没有则打印false,我们可以使用if else语句
-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
local booleans ex = false
for index,value in ipairs(myArrays)
do
if value == "world"
then
ex = true
break
end
end
if ex == true
then
print("true")
else
print("false")
end
-- 执行结果 true
(3).哈希
如果要使用类似于哈希的功能,同样可以使用tables类型,例如下面代码定义了一个tables,每个元素包含了key和value,其中strings1..strings2是将两个字符串进行连接。
-- 代码示例
local tables tom = {name = "tom",age = 18,height = 172.5}
print("姓名 : "..tom["name"]..",年龄 : "..tom["age"]..",身高 : "..tom["height"])
--执行结果
-- 姓名 : tom,年龄 : 18,身高 : 172.5
如果要遍历哈希,可以使用Lua的内置函数pairs
-- 代码示例
local tables tom = {name = "tom",age = 18,height = 172.5}
for key,value in pairs(tom)
do
print(key .. ":" .. value)
end
--执行结果
-- height:172.5
-- age:18
-- name:tom
函数定义
在Lua中,函数以function开头,以end结尾,funcName是函数名,中间部分是函数体。
-- function funcName()
-- ···
-- end
-- 例如写一个contact方法用来拼接两个字符串
function contact (str1 , str2)
return str1 .." ".. str2
end
print(contact("hello ","world"))
--执行结果 hello world
2.Redis与Lua
在Redis中使用Lua
在Redis中执行Lua脚本有两种方法:eval 和 evalsha
(1) eval
eval 脚本内容 key个数 key列表 参数列表
下面例子使用了key列表和参数列表来为Lua脚本提供更多的灵活性:
> eval 'return "hello ".. KEYS[1] .. " " .. ARGV[1]' 1 redis world
"hello redis world"
此时KEYS[1] = redis,ARGV[1] = world,所以最终的打印结果为 hello redis world
注意:KEYS 和 ARGV 一定要大写否则会报错,如下
> eval 'return "hello ".. keys[1] .. " " .. argv[1]' 1 redis world
"ERR Error running script (call to f_9f158bb8946915295cd6c488611b5004b5bf66c9): @user_script:1: user_script:1: Script attempted to access nonexistent global variable 'keys'"
> eval 'return "hello ".. KEYS[1] .. " " .. argv[1]' 1 redis world
"ERR Error running script (call to f_6248f0862bc574fb60782a2d632d7db773e16286): @user_script:1: user_script:1: Script attempted to access nonexistent global variable 'argv'"
如果不需要传KEYS或者ARGVS可以进行以下操作:
# 不传KEYS
> eval 'return "hello ".. ARGV[1] .. " " .. ARGV[2]' 0 redis world
"hello redis world"
# 不传ARGVS
> eval 'return "hello ".. KEYS[1] .. " " .. KEYS[2]' 2 redis world
"hello redis world"
如果Lua脚本过长,还可以直接使用redis-cli --eval 直接执行Lua脚本文件。
eval命令和--eval参数本质是一样的,客户端如果想执行Lua脚本,首先在客户端编写好Lua脚本代码,然后把脚本作为字符串发送给服务器,服务器端会将执行结果返回给客户端。
注意:这里的参数是需要使用逗号隔开的,逗号左右两边都需要有一个空格,没有参数则不填。
[root@xxx src]# cat /root/myredis/script/contactStr.lua
return ARGV[1].." "..ARGV[2]
[root@xxx src]# redis-cli -a xxx --eval /root/myredis/script/contactStr.lua , hello world
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"hello world"
整个过程如图所示
(2) evalsha
除了使用eval,Redis还提供了evalsha命令来执行Lua脚本。首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和,evalsha命令使用SHA1作为参数可以直接执行对应的Lua脚本,避免每次发送Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到了服用。
加载脚本:
script load命令可以将脚本内容加载到Redis内存中,例如下面将contactStr.lua脚本加载到Redis中,得到SHA1为:9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34
# 代码示例
[root@xxx src]# redis-cli -a xxx script load "$(cat /root/myredis/script/contactStr.lua)"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34"
执行脚本:
evalsha的使用方法如下,参数使用SHA1值,执行逻辑和eval一致。
evalsha 脚本SHA1值 key个数 key列表 参数列表
# 代码示例
[root@xxx src]# redis-cli -a xxx evalsha 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34 0 hello world
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"hello world"
Lua的Redis API
Lua可以使用redis.call函数实现对Redis的访问,例如下面的代码是Lua使用redis.call调用了Redis的set和get操作:
-- 代码示例
redis.call("set","hello","world")
redis.call("get","hello")
放在Redis的执行效果如下:
# 代码示例
> set hello world
"OK"
> eval 'return redis.call("get",KEYS[1])' 1 hello
"world"
除此之外Lua还可以使用redis.pcall函数实现对Redis的调用,redis.call和redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返回错误,而redis.pcall会忽略错误继续执行脚本。
3.Redis如何管理Lua
Redis提供了4个命令实现对Lua脚本的管理。
(1) script load
此命令用于将Lua脚本加载到Redis内存中
# 代码示例
[root@xxx src]# redis-cli -a xxx script load "$(cat /root/myredis/script/contactStr.lua)"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34"
(2) script exists
此命令用于判断sha1是否已经加载到Redis内存中
# 代码示例
> script exists 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34
1) "1"
因为这里的参数可以填多个,返回值为被加载到Redis内存中的Lua脚本个数。
(3) script flush
此命令用于清除Redis内存已经加载的所有Lua脚本。
# 代码示例
> script flush
"OK"
> script exists 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34
1) "0"
(4) script kill
此命令用于杀掉正在执行的Lua脚本。如果Lua脚本比较耗时,甚至Lua脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或者外部进行干预将其结束。
标签:..,--,redis,Lua,初级,world,hello From: https://www.cnblogs.com/lixiuxiu/p/18574681