RedisTemplate执行lua脚本问题(java.lang.IllegalStateException: null)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zl_momomo/article/details/83655811

1. ERR value is not an integer or out of range

@Bean
    public RedisTemplate redisTemplate(LettuceConnectionFactory redisConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //配置序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //使用GenericFastJsonRedisSerializer 代替 GenericJackson2JsonRedisSerializer
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
        return  redisTemplate;
    }
        RedisScript redisScript = RedisScript.of("local times = redis.call('incr',KEYS[1]) if times == 1 then redis.call('expire',KEYS[1],ARGV[1]) end if times > 5 then return 0 end return 1",Long.class);
        List<String> list = new ArrayList<>();
        list.add("door3");
        Object result = redisTemplate.execute(redisScript,list,"60");

报错 : @user_script:1: ERR value is not an integer or out of range

连接redis,观察lua脚本执行情况。

redis.call('incr',KEYS[1]) 执行成功,key值正确设值

redis.call('expire',KEYS[1],ARGV[1]) , 执行失败 ,并没有设置过期值。说明ARGV[1] 的设值出现问题

 

——> 观察源码

public <T> T execute(final RedisScript<T> script, final List<K> keys, final Object... args) {
		// use the Template's value serializer for args and result
		return execute(script, template.getValueSerializer(), (RedisSerializer<T>) template.getValueSerializer(), keys,
				args);
	}

使用的是 template 设置的ValueSerializer() ,上面我们设置的是GenericFastJsonRedisSerializer

——> 观察GenericFastJsonRedisSerializer 的序列化方式

public byte[] serialize(Object object) throws SerializationException {
        if (object == null) {
            return new byte[0];
        } else {
            try {
                return JSON.toJSONBytes(object, new SerializerFeature[]{SerializerFeature.WriteClassName});
            } catch (Exception var3) {
                throw new SerializationException("Could not serialize: " + var3.getMessage(), var3);
            }
        }
    }

 ——> 提取JSON.toJSONBytes 观察下列可知转换得的是“5” 的json字符串,不是数值5

byte[] bytes = JSON.toJSONBytes("5", new SerializerFeature[]{SerializerFeature.WriteClassName});
         System.out.println(new String(bytes).equals("\"5\""));// "5"  true

 

修改方式,redisTemplate.execute 中自己定义key和arg的序列化方式,我们使用StringRedisSerializer

Object result = redisTemplate.execute(redisScript,new StringRedisSerializer(),new StringRedisSerializer(),list,"60");

 

2.java.lang.IllegalStateException: null

RedisScript redisScript = RedisScript.of("local times = redis.call('incr',KEYS[1]) if times == 1 then redis.call('expire',KEYS[1],ARGV[1]) end if times > 5 then return 0 end return 1",
                Integer.class);

如果上述的RedisScript的ResultType 把Long改为Integer,也会报错。原因在于lua并不支持Integer类型

观察下列源码可以得到lua类型和java类型一个对应关系

// ReturnType.class  
public static ReturnType fromJavaType(@Nullable Class<?> javaType) {

		if (javaType == null) {
			return ReturnType.STATUS;
		}
		if (javaType.isAssignableFrom(List.class)) {
			return ReturnType.MULTI;
		}
		if (javaType.isAssignableFrom(Boolean.class)) {
			return ReturnType.BOOLEAN;
		}
		if (javaType.isAssignableFrom(Long.class)) {
			return ReturnType.INTEGER;
		}
		return ReturnType.VALUE;
	}

 

展开阅读全文

没有更多推荐了,返回首页