- RedisTemplate执行lua脚本
- 引入lua脚本。
DefaultRedisScript<List> redisScript = new DefaultRedisScript<List>();
//放在和application.yml 同层目录下
redisScript.setLocation(new ClassPathResource("test.lua"));
redisScript.setResultType(List.class);
- 运行lua脚本,keyList为传入的key值列表,需要加前缀,以确保在同一节点上,d为参数数组。
List<String> list = new ArrayList<>();
list.add("{pre}:door");
list.add("{pre}:dog");
String [] d = new String[10];
d[0] = String.valueOf(12);
d[1] = "22";
List<String> result = redisUtils.getRedisTemplate().execute(redisScript,list,d);
- 这里可以通过查看execute方法最后执行的源码可以看出:首先直接传sha值,如果在Redis中找不到预加载的lua脚本导致报错,则catch住该错误,把整个脚本序列化后传入Redis进行执行:
protected <T> T eval(RedisConnection connection, RedisScript<T> script, ReturnType returnType, int numKeys, byte[][] keysAndArgs, RedisSerializer<T> resultSerializer) {
Object result;
try {
result = connection.evalSha(script.getSha1(), returnType, numKeys, keysAndArgs);
} catch (Exception var9) {
if (!ScriptUtils.exceptionContainsNoScriptError(var9)) {
throw var9 instanceof RuntimeException ? (RuntimeException)var9 : new RedisSystemException(var9.getMessage(), var9);
}
result = connection.eval(this.scriptBytes(script), returnType, numKeys, keysAndArgs);
}
return script.getResultType() == null ? null : this.deserializeResult(resultSerializer, result);
}
- 注意:excute方法必须明确传key值,否则报:Lua script attempted to access a non local key in a cluster node错误。因为RedisTemplate操作的是集群,redis需要通过key值确定槽和节点。多个key的话,key值前都需要加{前缀}:,以确保都在同一个节点上的槽。
2.RedisTemplate预加载lua到redis
- Lua脚本运行之前都需要加载一次,为了减少网络开销,可在初始化时就将lua脚本预加载到redis中。通过redisTemplate 预加载lua脚本。返回的字符串为sha值。运行下面的代码后,再执行 redisUtils.getRedisTemplate().execute(redisScript,list,d)方法,源码中执行的就是第一步,是直接通过sha值运行Redis中提前加载好的lua脚本。
-
String s =redisUtils.getRedisTemplate().getConnectionFactory().getClusterConnection().scriptLoad(redisScript.getScriptAsString().getBytes());
原创不易,有用请点个赞。。