【更新】SpringBoot自带RedisTemplate执行lua脚本以及预加载lua脚本到Redis集群

  1. RedisTemplate执行lua脚本
  • 引入lua脚本。
        DefaultRedisScript redisScript = new DefaultRedisScript();
        //放在和application.yml 同层目录下
        redisScript.setLocation(new ClassPathResource("test.lua"));
        redisScript.setResultType(List.class);
  • 运行lua脚本,keyList为传入的key值列表,需要加前缀,以确保在同一节点上,d为参数数组。
        List 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 result = redisUtils.getRedisTemplate().execute(redisScript,list,d);
  • 这里可以通过查看execute方法最后执行的源码可以看出:首先直接传sha值,如果在Redis中找不到预加载的lua脚本导致报错,则catch住该错误,把整个脚本序列化后传入Redis进行执行:
protected  T eval(RedisConnection connection, RedisScript script, ReturnType returnType, int numKeys, byte[][] keysAndArgs, RedisSerializer 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());

     

 

 

原创不易,有用请点个赞。。

你可能感兴趣的:(redis)