Redis 更新key值导致过期时间失效问题

场景再现

首先,往redis里面存一个key,

然后,设置超时时间为300s,

 如下图所示

 紧接着,更新name的值,

 问题来了,重新设置了name的值之后,这个key的过期时间是多少呢?

A 过期时间无影响,就是剩余时间

B 过期时间重置为300s

C 清除掉超时时间,key永远有效

答案是什么呢?C

执行ttl name命令之后,可以看到返回值是-1,也就是永远有效。

答案很简单,问题的场景也很简单,我想大家都可以理解。

但是如果在一个大的项目需求里面,我们在设置key过期时间的时候,我们可能就会忽略这种超时时间被清除掉的场景,从而导致功能出错。

比方说,表里有编号1到10000的数据,有一个定时任务,每天早上6点开始,每5分钟执行一次,每次按顺序读取500条数据做相关处理。方案是使用redis记录每次读取的编号起始位置。

首先初始化key,并设置超时时间为6小时:

set max_num 1

设置超时时间一天

expire max_num 60*60*6

之后,每执行一次,更新max_num的值,

set max_num 501

set max_num 1001

。。。

直到读完这10000条数据。按照预想,第二天,继续从1开始读。

实际上,在执行set max_num 501的时候,过期时间就已经失效了,第二天会从10000开始读,并不会从1开始读。

当然,这只是某个会出错的场景。实际开发中,不知不觉可能会犯其它的错误。

补充key清楚的一些场景

如果用SET, GETSET会将key对应存储的值替换成新的,也会清除掉超时时间。

如果list结构中添加一个数据或者改变hset数据的一个字段是不会清除超时时间的。

INCR/LPUSH/HSET等命令则不会清除过期时间。

在使用INCR/LPUSH/HSET这种只是修改一个key的value,而不是覆盖整个value的命令,则不会清除key的过期时间。

如果想要通过set去覆盖值那就必须重新设置expire。

首先想到先获取过期时间,然后 set 时指定过期时间,但这样毕竟要两次请求,还有一种解决方案,使用 setrange 命令

setrange命令

Redis Setrange 命令用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始。

这个命令是覆写值,不会更改过期时间。
 


版权声明:本文为AttleeTao原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。