redis初级——Lua脚本

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"

整个过程如图所示

eval命令执行Lua脚本过程

(2) evalsha

​ 除了使用eval,Redis还提供了evalsha命令来执行Lua脚本。首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和,evalsha命令使用SHA1作为参数可以直接执行对应的Lua脚本,避免每次发送Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到了服用。

使用evalsha执行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,直到脚本执行完毕或者外部进行干预将其结束。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值