代碼如下:
/**
* 獲取分布式鎖
*
* @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 就好了