lua脚本语言小巧轻便,运行性能优异,被很多语言作为嵌入式脚本语言使用redislua脚本语言有很好的支持,对于开发者,如果要处理数据涉及到只是简单计算逻辑,就不必将redis中的数据拿到应用程序执行了,直接写一段lua脚本程序可以redis服务端完成逻辑处理
有关lua语言语法内容这里就不做过多的介绍,这里只是介绍redis如何运行lua脚本

  1. 命令行运行脚本

redis命令行运行lua脚本非常简单,只需要定义好lua代码字符串,在redis客户端使用 eval 命令运行脚本,命令格式如下

127.0.0.1:6379> eval script numkeys key [key ...] arg [arg ...]

script :是要执行的lua脚本字符串
numkeyskey的数量,如果没有这个数就设置为0
keykey的具体值,key的数量要与前面定义的数量保持一致
arg参数列表

下面演示一下如何使用上面的命令:

127.0.0.1:6379> eval "return 'hello,world!';" 0 
"hello,world!"
127.0.0.1:6379> 
127.0.0.1:6379> eval "return redis.call('set', KEYS[1], ARGV[1]);" 1 lua_key lua_val
OK
127.0.0.1:6379> 
127.0.0.1:6379> eval "return redis.call('get', KEYS[1]);" 1 lua_key
"lua_val"
127.0.0.1:6379> 
127.0.0.1:6379> eval "if redis.call('exists', KEYS[1]) > 0 then return redis.call('get', KEYS[1]); else return ''; end;" 1 kkkk 
""
127.0.0.1:6379> 
127.0.0.1:6379> eval "if redis.call('exists', KEYS[1]) > 0 then return redis.call('get', KEYS[1]); else return ''; end;" 1 lua_key 
"lua_val"
127.0.0.1:6379> 

在lua脚本中调用redis命令使用 redis.call() 方法方法第一个参数是命令的名称,后面跟参数所有的键放入KEYS中,值放入ARGV中,在脚本中参数下标从1开始。
除了上面的调用方式我们可以将lua脚本写入系统文件中,然后通过命令行调用本地文件执行
我们系统新建一个lua脚本文件,命名为lua_script.lua,内容如下

local exist = redis.call('exists', KEYS[1]);
if exist > 0 then
  local rs = redis.call('incrby', KEYS[1], ARGV[1]);
  return '1_' .. rs;   // 这里是lua中的字符串拼接方法str1 .. str2 会将两个字符拼接成一个字符else 
  local rs = redis.call('set', KEYS[1], ARGV[2]);
  if rs then
    local rs = redis.call('incrby', KEYS[1], ARGV[1]);
    return '2_' .. rs;
  else
    return nil;
  end;
end;

脚本的执行流程是:先判断是否存在,如果存在直接执行incrby指令进行加数操作;如果不存在,先初始化键的值,然后再执行incrby指令进行加数操作。

lua脚本文件执行调用命令是:

redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3

–eval 表示执行lua脚本文件,后面跟着的就是脚本文件路径可以相对路径可以绝对路径接下来就是所有的键和值,键和值之间使用”,”分隔多个键和多个之间使用空格分隔
例如,要调用上面写好的脚本文件使用下面的命令:

[root@localhost src]# ./redis-cli --eval /root/lua_scripts/lua_script.lua incr:key:0001 , -2 200
"2_198"
[root@localhost src]# 
[root@localhost src]# ./redis-cli --eval /root/lua_scripts/lua_script.lua incr:key:0001 , -2 200
"1_196"
[root@localhost src]# 
  1. 代码中使用lua脚本

命令行中运行lua脚本在实际项目其实并不常用,更多的是在代码中执行lua脚本,下面演示在代码中如何使用lua脚本,先演示redisTemplate中的使用:
在redisTemplate中使用lua脚本需要调用redisTemplate.execute(RedisScript script, List keys, Object… args)方法,该方法第一个参数是lua脚本,第二个参数是键列表第三参数一个不定个数的值数组。使用方式如下

String lua = "return redis.call('set', KEYS[1], ARGV[1]);";
DefaultRedisScript<String> script = new DefaultRedisScript<>(lua, String.class);

List<String> keys = Collections.singletonList("java:lua:key");
String rs = redisTemplate.execute(script, keys, "java_lua_value");

除了上面这种定义lua脚本方式,还可以一个lua脚本文件,在程序中调用这个lua脚本文件执行,代码如下

DefaultRedisScript<String> script = new DefaultRedisScript<>();
script.setResultType(String.class);
script.setScriptSource(new ResourceScriptSource(new FileSystemResource("E:\lua_script.lua")));
List<String> keys = Collections.singletonList("ncr:key:0001");
String rs = redisTemplate.execute(script, keys, "-2", "200");

如果项目使用的是jedis,代码就跟redis客户执行命令一样:

String script = "return redis.call('get', KEYS[1]);";
Object rs = jedis.eval(script, 1, "incr:key:0001");
System.out.println(rs);

redis还提供了使用evalsha()方式执行lua脚本,这种方式是先将lua脚本在服务端缓存客户端只需要传递过去缓存脚本的编码可以调用lua脚本执行:
比如服务端加载一个lua脚本并生成了编码:

127.0.0.1:6379> script load "return redis.call('get', KEYS[1]);"
"796941151549c416aa77522fb347487236c05e46"
127.0.0.1:6379> 

这时在客户端要执行lua脚本只需要执行下面的方法:

Object rs = jedis.evalsha("796941151549c416aa77522fb347487236c05e46", 1, "incr:key:0001");
System.out.println(rs);

使用redisTemplate调用evalsha需要redisTemplate的execute()方法,它类似redis原生命令,请求返回数据都是byte数组

Object rs = redisTemplate.execute(new RedisCallback<Object>() {
    @Override
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
        byte[] rs = connection.evalSha("796941151549c416aa77522fb347487236c05e46", ReturnType.VALUE, 1, "incr:key:0001".getBytes(StandardCharsets.UTF_8));
        return new String(rs);
    }
});
System.out.println(rs);

上面这种方式性能最好的,因为脚本都是在服务端缓存起来了,省去了数据提交时的性能损耗。但是在项目应该很少被使用,因为一旦redis宕机,意味着缓存的脚本编码都将失效,那么程序运行就会出问题

在redis中使用lua脚本非常好用可以将一些简单处理逻辑服务端就执行了,避免数据的来回传输。使用lua脚本也可以让多个命令执行保持原子性,在lua脚本执行中间不能插入其他的redis命令。由于lua脚本都是整体运行的,所以也不建议在lua脚本中执行非常耗时的命令,或者一个lua脚本中执行过多的命令,这样会导致服务响应其他的请求等待时间超时

原文地址:https://blog.csdn.net/dream_xin2013/article/details/134812585

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_47450.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注