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

本文探讨了Redis中键的过期时间和值更新的关系,指出在执行`SET`等命令时可能会清除键的过期时间,导致预期功能失效。例如,一个用于记录数据处理进度的键如果没有正确处理过期时间,可能导致处理从错误的位置开始。解决方案包括在更新值时重新设置过期时间或使用`SETRANGE`命令。开发者应注意在大型项目中避免此类错误,确保键的过期策略符合需求。
摘要由CSDN通过智能技术生成

场景再现

首先,往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 开始。

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

### 回答1: 在 Redis 中,我们可以使用 KEYS 命令来获取所有的 key,但是这个命令性能比较差,因为它会遍历整个 Redis 数据库。为了避免这个问题,我们可以使用 Redis 的发布订阅机制来监听 key 失效事件。 具体步骤如下: 1. 首先我们需要在代码中订阅一个特定的频道,用于接收 key 失效事件的通知。可以使用 Redis 的 SUBSCRIBE 命令来完成订阅操作: ``` SUBSCRIBE __keyevent@0__:expired ``` 2. 接着,我们需要在 Redis 中设置一个 key,并为其设置过期时间。在 key 过期后,Redis 会自动发布一条消息到指定的频道中,我们可以在代码中接收这个消息: ``` SET mykey "hello world" EXPIRE mykey 60 ``` 3. 最后,我们需要编写一个消息处理函数,用于接收并处理 Redis 发布到频道中的消息。在 Python 中,可以使用 Redis 的 Python 客户端库 redis-py 来实现这个功能: ```python import redis r = redis.Redis(host='localhost', port=6379, db=0) def handle_message(message): print(message) pubsub = r.pubsub(ignore_subscribe_messages=True) pubsub.subscribe('__keyevent@0__:expired') for message in pubsub.listen(): handle_message(message['data']) ``` 在上面的代码中,我们首先创建了一个 Redis 客户端对象,并定义了一个消息处理函数 handle_message。然后,我们创建了一个 pubsub 对象,并使用 ignore_subscribe_messages 参数来忽略订阅时产生的消息。接着,我们使用 subscribe 方法来订阅指定的频道,并使用 listen 方法来循环接收 Redis 发布到频道中的消息,并将其传递给 handle_message 函数进行处理。 当我们运行上面的代码并设置了一个 key过期时间后,如果这个 key 过期了,Redis 就会自动发布一条消息到指定的频道中,我们就可以在代码中接收到这个消息,并进行相应的处理了。 ### 回答2: 监听Redis缓存过期事件(Key失效事件)可以通过Redis的订阅发布功能来实现。在Redis中,可以通过配置键空间通知(keyspace notifications)来启用这个功能。 首先,我们需要在Redis配置文件中打开键空间通知功能。可以通过修改redis.conf文件中的`notify-keyspace-events`参数来开启键空间通知。例如,可以将其设置为`Ex`,表示启用键过期事件的通知。 启用键空间通知后,我们可以使用`SUBSCRIBE`命令来订阅指定的频道,以便监听特定事件。对于键过期事件,我们可以订阅`__keyevent@0__:expired`频道。 以下是监听Redis缓存过期事件的示例代码: ``` import redis def event_handler(message): print("Key expired:", message['data']) def main(): r = redis.Redis(host='localhost', port=6379, db=0) pubsub = r.pubsub() pubsub.subscribe('__keyevent@0__:expired') for message in pubsub.listen(): if message['type'] == 'message': event_handler(message) if __name__ == "__main__": main() ``` 在上述示例代码中,我们使用Python的`redis`模块来连接Redis,并创建一个订阅对象`pubsub`。然后,我们使用`subscribe`方法来订阅`__keyevent@0__:expired`频道,并通过循环监听事件。 当有键过期事件发生时,`event_handler`函数会被调用,并打印出相应的信息。 通过以上代码,我们可以在Redis中实现监听缓存过期事件的功能。当监听到键过期事件时,可以做相应的处理操作,例如重新加载缓存数据或执行其他业务逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

架构帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值