当前位置: 首页 > 工具软件 > x-redis > 使用案例 >

Lua入门和使用Redis、Redisson、Spring-data-redis调用Lua脚本

梁英喆
2023-12-01

Lua简介


Lua是一种开源、简单易学、轻量小巧的脚本语言,用标准C语言编写。

其设计的目的就是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Redis从2.6版本开始支持Lua脚本,Redis使用Lua可以:

  1. 原子操作。Redis会将整个脚本作为一个整体执行,不会被中断。可以用来批量更新、批量插入
  2. 减少网络开销。多个Redis操作合并为一个脚本,减少网络时延
  3. 代码复用。客户端发送的脚本可以存储在Redis中,其他客户端可以根据脚本的id调用。

入门


安装

Linux安装Lua :

curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install

第一个lua脚本

编写Hello.lua文件:

print('hello world')

执行命令:

lua Hello.lua

基本语法

Lua提供交互式编程,可以在命令行中输入命令并立即查看结果。

Lua脚本也可以保存在一个以lua为结尾的文件,并执行。

Lua注释的符号是两个减号 :

-- 这是一行注释
--[[
	这是多行注释
--]]
print('这是一行代码')

Lua的关键字 :

andbreakdoelse
elseifendfalsefor
functionifinlocal
nilnotorrepeat
returnthentrueuntil
whilegoto

Lua中的变量总是全局的。

数据类型

Lua有八个基本类型:

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

    print(a)
    

    a是未初始化的,打印a就会输入nil值。

  2. boolean

    boolean类型有两个值:truefalseLua也会把nil当成false值,但false不等于nil。与C语言不一样,0Lua中是true

    print(a == nil) -- true
    print(false == nil) -- false
    if(a) then
        print(1)
    else
        print(0) -- print 0
    end
    
  3. number

    number默认只有一种类型:double

  4. string

    string可以用双引号、单引号来表示,也可以用[[]]来表示一块字符串。

    str = [[
        中括号中的字符串会报保
            留tab和换行
    ]]
    print(str)
    

    string在与number进行算数运算,会尝试将字符转化为数字

    numStr = '1'
    num = 3
    print(numStr + num) -- print 4
    

    使用#计算字符串的长度:

    print(#'这是一行字符串')
    
  5. table

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

    Lua的数组从1开始。

  6. function

  7. thread

  8. userdata

变量

Lua的变量默认为全局变量,声明局部变量使用local关键字。

循环

Lua中的循环有 :whileforrepeat

while循环

a=10
while( a < 20 )
do
   print("a 的值为:", a)
   a = a+1
end

For循环

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

Repeat循环

--[ 变量定义 --]
a = 10
--[ 执行循环 --]
repeat
   print("a的值为:", a)
   a = a + 1
until( a > 15 )

使用breakgoto可以跳出循环。

关系运算符

操作符描述实例
== 等于,检测两个值是否相等,相等返回 true,否则返回 false (A == B) 为 false。
~= 不等于,检测两个值是否相等,相等返回 false,否则返回 true (A ~= B) 为 true。
> 大于,如果左边的值大于右边的值,返回 true,否则返回 false (A > B) 为 false。
< 小于,如果左边的值大于右边的值,返回 false,否则返回 true (A < B) 为 true。
>= 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false (A >= B) 返回 false。
<= 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false (A <= B) 返回 true。

逻辑运算符

操作符描述实例
and 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 (A and B) 为 false。
or逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 (A or B) 为 true。
not逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 not(A and B) 为 true。

其他运算符

操作符描述实例
..连接两个字符串 a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。
#一元运算符,返回字符串或表的长度。#"Hello" 返回 5

与Redis搭配使用


Redis使用Lua脚本主要用三个命令 :

  • eval :执行脚本
  • evalsha :根据id调用存储在Redis中的脚本
  • script load :将脚本保存在Redis中

示例:

eval "redis.call('set',KEYS[1],ARGV[1])" 1 K1 'V1'
eval "return redis.call('get',KEYS[1])" 1 K1
EVAL script numkeys key [key ...] arg [arg ...] 
-- numberkeys是key的个数

使用Spring-data-redis调用脚本


DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();

redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/BATCH_UPDATE.lua")));

redisScript.setResultType(Boolean.class);

redisTemplate.execute(redisScript, Collections.singletonList(key), Collection.singletonList(fakeDataList));
local dataStr = KEYS[1]
local dataList = loadstring("return"..dataStr)
for index,data in dataList do
    redis.call('SET',data[name],'EX',data[timeInterval])
end
return true

Redisson调用Lua脚本


redisson.getBucket("foo").set("bar");
String r = redisson.getScript().eval(Mode.READ_ONLY,
   "return redis.call('get', 'foo')", RScript.ReturnType.VALUE);

// 通过预存的脚本进行同样的操作
RScript s = redisson.getScript();
// 首先将脚本保存到所有的Redis主节点
String res = s.scriptLoad("return redis.call('get', 'foo')");
// 返回值 res == 282297a0228f48cd3fc6a55de6316f31422f5d17

// 再通过SHA值调用脚本
Future<Object> r1 = redisson.getScript().evalShaAsync(Mode.READ_ONLY,
   "282297a0228f48cd3fc6a55de6316f31422f5d17",
   RScript.ReturnType.VALUE, Collections.emptyList());

补充

当 Redis 的 持久化策略为 RDB 情况下,不会对脚本进行持久化!!!
当 Redis 的 持久化策略为 RDB 情况下,不会对脚本进行持久化!!!
当 Redis 的 持久化策略为 RDB 情况下,不会对脚本进行持久化!!!

 类似资料: