今天给大家分享的是Redis基础命令set
过期时间被覆盖问题。该命令可能是大家最为常见的一个命令,但有一个小细节可能很多人多都没注意到,今天就来演示总结一下。
该细节虽然看着很小,平常也很少关注到这点。但在实际的生产环境发生过一次,对于一些流量大的应用尤其需要注意。
首先我们按照常规的操作,向Redis中插入一个值。示例代码如下:
127.0.0.1:6379> set demo kert ex 100OK127.0.0.1:6379> ttl demo(integer) 87
上面的命令不难看出,向Redis中插入了一个string类型的值,key为demo,值为kert,并且为其设置了一个过期时间。
接下来,我们对该key进行重新设值(update操作)。
127.0.0.1:6379> set demo bruce OK
看到这里,我们先思考3秒钟,该key的过期时间是多少?
过期时间可能是第一次设置时间
永不过期
带着这两种疑问,我们看看实际的结果。
127.0.0.1:6379> ttl demo(integer) -1
实际上结果变成了-1。-1是什么意思呢,在Redis中要查看某个key的过期时间,我们可以使用ttl命令
。它会返回三种可能的值:
如果为 >= 0 则是该key的剩余过期时间,返回的时间是秒(s),如果想返回毫秒,可以使用pttl
如果为 -1 则是该key没有设置过期时间
如果为 -2 则是该key不存在,可能是本身就不存在也有可能是该key已到过期时间,被Redis标记为过期的key
通过实际的演示,我们返现使用set命令时,会覆盖原本key的过期时间,并且将该key设置为永久不失效的key。
要保持该key的过期时间,这里有两种方案:
先获取该key的过期时间,如果设置了过期时间,重新赋值之后再对其设置过期时间
使用Redis6.0版本之后的新命令参数,keepttl
示例代码如下:
127.0.0.1:6379> set demo bruce ex 100OK127.0.0.1:6379> ttl demo(integer) 96127.0.0.1:6379> set demo 7small7 OK127.0.0.1:6379> ttl demo(integer) -1127.0.0.1:6379> expire demo 96(integer) 1127.0.0.1:6379> ttl demo(integer) 93
上述代码,大致的逻辑就是先设置一个带过期时间的key,并且在重新赋值前,获取过期时间,重新赋值之后再对key设置原来的过期时间。
该方式有2个大的问题,过期key的时间差,以及多个命令执行的原子性。
上述第1种的解决方案存在两个问题,接下来我们使用官方提供的命令参数。
127.0.0.1:6379> set demo bruce ex 100OK127.0.0.1:6379> ttl demo(integer) 96127.0.0.1:6379> set demo 1111 keepttl OK127.0.0.1:6379> ttl demo(integer) 82
通过上面的操作,可以看到key的过期时间还是原有的过期时间。并且命令属于原子性操作,不用担心某个命令操作失败的问题。
最后还需要注意一点:官方原本提供了SETNX
, SETEX
, PSETEX
, GETSET
等命令,但现在官方推荐不要使用这样的命令,在将来这些命令可能会被移除,而推荐是SET
命令+参数
的方式来实现。
Note: Since the SET command options can replace SETNX, SETEX, PSETEX, GETSET, it is possible that in future versions of Redis these commands will be deprecated and finally removed.
有话要说