Redis在2.6版推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。在Lua脚本中可以调用大部分的Redis命令,使用脚本的好处如下。
(1)减少网络开销:在Redis操作需求需要向Redis发送5次请求,而使用脚本功能完成同样的操作只需要发送一个请求即可,减少了网络往返时延。
(2)原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。换句话说在编写脚本的过程中无需担心会出现竞态条件,也就无需使用事务。事务可以完成的所有功能都可以用脚本来实现。
(3)复用:客户端发送的脚本会永久存储在Redis中,这就意味着其他客户端(可以是其他语言开发的项目)可以复用这一脚本而不需要使用代码完成同样的逻辑。
1-1.Lua语言
这里不会完整的介绍Lua语言中的所有要素,而是只着重编写Redis脚本会用到的部分。《愤怒的小鸟》就是使用Lua语言实现的关卡。
1).数据类型
数据类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表 local tbl1 = {}。 |
Lua的变量分为全局变量和局部变量。全局变量无需声明就可以直接使用,默认值是nil。如:
a = 5 -- 为全局变量a赋值
print(b) -- 无需声明即可使用,默认是nil
a = nil -- 删除全局变量a的方法是将其赋值为nil,全局变量没有声明和未声明之分,
只有nil和非nil的区别
在Redis脚本中不能使用全局变量,只允许使用局部变量以防止脚本之间相互影响。用 local 显示声明为局部变量。
local c -- 声明一个局部变量,默认值是nil
local d=1 -- 声明一个局部变量d并赋值为1
local e,f -- 可以同时声明多个局部变量
同时声明一个存储函数的局部变量的方法为:
local say_hi = function()
print 'hi'
end
变量名必须是非数字开头,只能包含字母、数字和下划线,区分大小写。变量名不能与Lua的保留关键字相同。
局部变量的作用域为从声明开始到所在层的语句块末尾,比如:
local x=10
if true then
local x=x+1
print(x)
do
local x=x+!
print(x)
end
end
print(x)
结果为:
11,12,11,10
3).注释
Lua的注释有单行和多行两种。单行注释以--开始,到行尾结束,一般习惯在--后面跟上一个空格。多行注释以--[[ 开始,到]]结束。
4).赋值
Lua支持多重赋值,在执行多重赋值时,Lua会先计算所有表达式的值.如
local a,b = 1,2 -- a的值是1,b的值是2
local c,d = 1,2,3 -- c的值是1,d的值是2,3被舍弃了
local e,f=1 -- e的值是1,f的值是nil
5).操作符
①数学操作符:如+,-,*,/,%(取模)等
数学操作符的操作数如果是字符串会自动转换成数字,比如
print('1' + 1) -- 2
②比较操作符:如==,~=, <,>等
比较操作符的结果一定是布尔类型。比较操作符不同于数学操作符,不会对两边的操作数进行自动类型转换,需要手动进行类型转换,也就是说;
print(1 == '1') -- false
print({'a'} == {'a'}) -- false,对于表类型值比较的是二者的引用
print(1== tonumber('1')) -- true
③逻辑操作符:如not,and,or
只要操作数不是nil或false,逻辑操作符就认为操作数是真,否则是假。特别需要注意的是即使是0或空字符串也被当作真。
print(1 and 5) -- 5 a and b,如果a是真则返回b,否则返回b
print(1 or 5) -- 1 a or b,如果a是真则返回a,
print(not 0) -- false 根据操作数的真假返回true和false
④连接操作符:只有一个:..。用来连接两个字符串,连接操作符会自动把数字类型的值转换成字符串类型.如
print('hello' .. ' ' .. 'world!') -- 'hello world!'
⑤取长度操作符。只有一个:#。用来获取字符串或表的长度
print(#'hello') -- 5