springboot redis 用RedisTemplate执行lua脚本报错:@user_script:1: ERR value is not an integer or out of range

代码如下:

/**
* 获取分布式锁
*
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 单位秒|你认为此方法需要多少时间,设置一个最长时间,此时间必须大于需要调用锁的业务方法逻辑的最大时间,否则锁会冲突
* @param waitTimeout 单位毫秒|如果拿不到锁,那么休眠,然后反反复复重试,直到拿到锁为止
* demo redisService.getLock("lock", uuid, 10, 1500) 调用方法的业务逻辑最多需要1秒执行完成,1500毫秒一直等待(默认休眠500毫秒一次轮回)线程不执行,等到1500毫秒到了,才执行完整个方法
* @return 是否获取成功
*/
public boolean getLock(String lockKey, String requestId, long expireTime, long waitTimeout) {
// 当前时间
long nanoTime = System.nanoTime();
try {
String script = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end";
logger.debug("开始获取分布式锁-key[{}]", lockKey);
int count = 0;
List<String> lockKeyList = Collections.singletonList(lockKey);
do {
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
logger.debug("尝试获取分布式锁-key[{}]requestId[{}]count[{}]", lockKey, requestId, count);

Object result = redisTemplate.execute(redisScript, lockKeyList, requestId, expireTime + "");
Long SUCCESS = 1L;
if (SUCCESS.equals(result)) {
logger.debug("尝试获取分布式锁-key[{}]成功", lockKey);
return true;
}
//休眠200毫秒
Thread.sleep(200L);
count++;
} while ((System.nanoTime() - nanoTime) < TimeUnit.MILLISECONDS.toNanos(waitTimeout));
} catch (Exception e) {
e.printStackTrace();
logger.error("尝试获取分布式锁-key[{}]异常", lockKey);
logger.error(e.getMessage(), e);
}
return false;
}

/**
* 释放锁
*
* @param lockKey 锁
* @param value 请求标识
* @return 是否释放成功
*/
public boolean releaseLock(String lockKey, String value) {
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value);
Long SUCCESS = 1L;
if (SUCCESS.equals(result)) {
logger.debug("释放锁成功key[{}]value[{}]", lockKey, value);
return true;
}
return false;
}

错误如下:

org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR Error running script (call to f_dce7e03aa7a8103dc00e40ebb8e287d7d499bd3a): @user_script:1: ERR value is not an integer or out of range
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:54)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:52)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:268)
at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.convertLettuceAccessException(LettuceScriptingCommands.java:236)
at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.evalSha(LettuceScriptingCommands.java:195)
at org.springframework.data.redis.connection.DefaultedRedisConnection.evalSha(DefaultedRedisConnection.java:1318)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61)
at com.sun.proxy.$Proxy148.evalSha(Unknown Source)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.eval(DefaultScriptExecutor.java:77)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.lambda$execute$0(DefaultScriptExecutor.java:68)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:171)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:58)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:52)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:346)

分析,可能是值的类型不对或长度太长了?

1、修改value 的长度以后错误仍然存在。

2、在分析是不是返回值的类型不对,改为Integer后,又抛出另一个错误

org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: java.lang.IllegalStateException
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:74)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:268)
at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.convertLettuceAccessException(LettuceScriptingCommands.java:236)
at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.evalSha(LettuceScriptingCommands.java:195)
at org.springframework.data.redis.connection.DefaultedRedisConnection.evalSha(DefaultedRedisConnection.java:1318)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61)
at com.sun.proxy.$Proxy148.evalSha(Unknown Source)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.eval(DefaultScriptExecutor.java:77)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.lambda$execute$0(DefaultScriptExecutor.java:68)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:171)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:58)
at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:52)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:346)

3、改为String类型以后错误仍然存在。

最后百度可能是值序列化的问题,

4、修改RedisConfig

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
改为:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(factory);
  RedisSerializer stringRedisSerializer = new StringRedisSerializer();
  redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(stringRedisSerializer);

return redisTemplate;
}

  嘿嘿,果然可以了,就是redis 值序列化的问题, 默认的是JdkRedisSeerializer,改为StringRedisSerializer 就好了

原文地址:https://www.cnblogs.com/fancy2041/p/13213358.html