1、调用Lua脚本的语法:
$ redis-cli –eval path/to/redis.lua KEYS[1] KEYS[2] , ARGV[1] ARGV[2] …
–eval,告诉redis-cli读取并运行后面的lua脚本 path/to/redis.lua,是lua脚本的位置 KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取 ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
注意: KEYS和ARGV中间的 ‘,’ 两边的空格,不能省略。
redis支持大部分Lua标准库
| 库名 | 说明 |
|---|---|
| Base | 提供一些基础函数 |
| String | 提供用于字符串操作的函数 |
| Table | 提供用于表操作的函数 |
| Math | 提供数学计算函数 |
| Debug | 提供用于调试的函数 |
2、在脚本中调用redis命令
在脚本中可以使用redis.call函数调用Redis命令
redis.call(‘set’, ‘foo’, ‘bar’) local value=redis.call(‘get’, ‘foo’) –value的值为bar
redis.call函数的返回值就是Redis命令的执行结果
Redis命令的返回值有5种类型,redis.call函数会将这5种类型的回复转换成对应的Lua的数据类型,具体的对应规则如下(空结果比较特殊,其对应Lua的false)
redis返回值类型和Lua数据类型转换规则
| redis返回值类型 | Lua数据类型 |
|---|---|
| 整数回复 | 数字类型 |
| 字符串回复 | 字符串类型 |
| 多行字符串回复 | table类型(数组形式) |
| 状态回复 | table类型(只有一个ok字段存储状态信息) |
| 错误回复 | table类型(只有一个err字段存储错误信息) |
redis还提供了redis.pcall函数,功能与redis.call相同,唯一的区别是当命令执行出错时,redis.pcall会记录错误并继续执行,而redis.call会直接返回错误,不会继续执行。在脚本中可以使用return语句将值返回给客户端,如果没有执行return语句则默认返回nil
Lua数据类型和redis返回值类型转换规则
| Lua数据类型 | redis返回值类型 |
|---|---|
| 数字类型 | 整数回复(Lua的数字类型会被自动转换成整数) |
| 字符串类型 | 字符串回复 |
| table类型(数组形式) | 多行字符串回复 |
| table类型(只有一个ok字段存储状态信息) | 状态回复 |
| table类型(只有一个err字段存储错误信息) | 错误回复 |
3、脚本相关命令
EVAL语法: eval script numkeys key [key …] arg [arg …] 通过key和arg这两类参数向脚本传递数据,它们的值在脚本中分别使用KEYS和ARGV两个表类型的全局变量访问。 script: 是lua脚本 numkeys:表示有几个key,分别是KEYS[1],KEYS[2]…,如果有值,从第numkeys+1个开始就是参数值,ARGV[1],ARGV[2]… 注意: EVAL命令依据参数numkeys来将其后面的所有参数分别存入脚本中KEYS和ARGV两个table类型的全局变量。当脚本不需要任何参数时,也不能省略这个参数(设为0)
Java中使用Redis调用lua
public Integer isAccessed(String tenantId, String appCode, Long offset,Integer totalCount) throws BusinessException {
String key = Constants.SYSCODE + "_" + tenantId + "_" + appCode;
//lua脚本
String script = "local accessed = redis.call('getbit',KEYS[1],ARGV[1]);" + //判断是否已经访问过
" local totalCount = redis.call('bitcount',KEYS[1]);" +
"if (accessed==1) then " +
" return 0; " + //已经访问过 直接放过
"elseif(tonumber(ARGV[2]) > 0 and totalCount >= tonumber(ARGV[2])) then " +
" return 1;" + //人数超量
" else " +
" redis.call('setbit',KEYS[1],ARGV[1],1);" + //人数未超,添加到缓存中
" return 2;" +
" end";
List<String> keys = Lists.newArrayList(key);
List<String> args = Lists.newArrayList(offset.toString(),totalCount.toString());
return jedisTemplate.getShard(key).execute(new JedisTemplate.JedisAction<Integer>() {
public Integer action(Jedis jedis) {
return Integer.parseInt(jedis.eval(script,keys, args).toString());
}
});
}