这几天项目做了个定时任务,刚开始好着,后来一直没数据,看日志显示没拿到锁(拿key返回false)
总结一下,各位也避免这样😂 (想直接知道结果的请翻至最底↓💣):
刚开始🙏:
设置RedisService 获取锁的方法
/**
* 获取锁,设置过期时间(s)
* @param key key
* @param value 值
* @param outTime 超时时间s
* @return java.lang.Boolean
*/
public Boolean lock(String key, String value, long outTime) {
return redisTemplate.opsForValue().setIfAbsent(key, value, outTime, TimeUnit.SECONDS);
}
后来第二天再次去执行任务:
查看日志直接报错,显示拿不到锁,导致任务没有执行
发现问题所在😏:
虽然第一次设置了这个lockKey的过期时间,但是后来在后面对这个key再次进行了设置值
这就是问题的所在😅!!!
举个栗子🌰:
Boolean test = redisService.lock("test", "1", 10);
log.info(String.valueOf(test));
Boolean test1 = redisService.lock("test", "1", 10);
log.info(String.valueOf(test1));
redisService.set("test", "2");
结果:👇
这样看,确实没错,当执行到第五✋行,也就是设置值之后,再次去redis查看他的过期时间
他的TTL成了 -1 !!!
总结📏:
虽然之前对某个key设置了过期时间,但!如果再次进行赋值(用DEL, SET, GETSET会将key对应存储的值替换成新的),没有在后面expire,就会把过期时间覆盖掉,变成无限存活,也就是-1。
'-1' 如果不明白的童鞋看下面👇👇
Tips📌:
TTL 命令以秒为单位返回 key 的剩余过期时间。
当 key 不存在时,返回 -2 。
当 key 存在但没有设置剩余生存时间时,返回 -1 。
否则,以秒为单位,返回 key 的剩余生存时间。
注意:在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。
栗子🌰:
# 不存在的 key
redis> TTL key
(integer) -2
redis> SET mykey "Hello"
"OK"
# key 存在,但没有设置剩余生存时间
redis> TTL mykey
(integer) -1
# 有剩余生存时间的 key
redis> EXPIRE key 10086
(integer) 1
另一种解决方法😁:
说是解决方法,也可以说是一种习惯--->
在有必要的前提下,可以给代码加入try-catch-finally在finally中进行释放锁
try {
boolean lock = redisService.lock(lockKey, "1",10 * 60);
if (!lock) {
log.info("未获取到锁,不需要执行");
}
}catch (Exception e){
log.error("异常: ", e);
}finally {
redisService.unLock(lockKey);
}
这样之后不管这个key有没有进行过期操作 -> 都可以在程序执行之后进行“处理”
/**
* 解锁
*/
public Boolean unLock(String key) {
return this.delete(key);
}
当然,在写代码当中也需要去注意这种前后影响问题!!