SET 命令的 EX 选项和 PX 选项
在使用键过期功能时,组合使用 SET
命令和 EXPIRE
/ PEXIRE
命令的做法非常常见,比如上面展示的带有自动移除特性的缓存程序就是这样做的。
因为 SET
命令和 EXPIRE
/ PEXPIRE
命令组合使用的情况是如此的常见,所以为了方便用户使用这两组命令,Redis 从 2.6.12 版本开始为 SET
命令提供 EX
选项和 PX
选项,用户可以通过使用这两个选项的其中一个来达到同时执行 SET
命令和 EXPIRE
/ PEXPIRE
命令的效果:
- SET key value [EX seconds] [PX milliseconds]
这也就是说,如果我们之前执行的是 SET
命令和 EXPIRE
命令:
- SET key value
- EXPIRE key seconds
那么现在只需要执行一条带有 EX
选项的 SET
命令就可以了:
- SET key value EX seconds
与此类似,如果我们之前执行的是 SET
命令和 PEXPIRE
命令:
- SET key value
- PEXPIRE key milliseconds
那么现在只需要执行一条带有 PX
选项的 SET
命令就可以了:
- SET key value PX milliseconds
组合命令的安全问题
使用带有 EX
选项或 PX
选项的 SET
命令除了可以减少命令的调用数量并提升程序的执行速度之外,更重要的是保证了操作的原子性,使得“为键设置值”和“为键设置生存时间”这两个操作可以一起执行。
比如说,前面在实现带有自动移除特性的缓存程序时,我们首先使用了 SET
命令设置缓存,然后又使用了 EXPIRE
命令为缓存设置生存时间,这相当于让程序依次地向 Redis 服务器发送以下两条命令:
- SET key value
- EXPIRE key timeout
因为这两条命令是完全独立的,所以服务器在执行它们的时候,就可能会出现 SET
命令被执行了,但是 EXPIRE
命令却没有被执行的情况。比如说,如果 Redis 服务器在成功执行 SET
命令之后因为故障下线,导致 EXPIRE
命令没有被执行,那么 SET
命令设置的缓存就会一直存在,而不会因为过期而自动被移除。
与此相反,使用带有 EX
选项或 PX
选项的 SET
命令就没有这个问题:当服务器成功执行了一条带有 EX
选项或 PX
选项的 SET
命令时,键的值和生存时间都会同时被设置好,因此程序就不会出现只设置了值但是却没有设置生存时间的情况。
基于上述原因,我们把前面展示的缓存程序实现称之为“不安全”(unsafe)实现。为了修复这个问题,我们可以使用带有 EX
选项的 SET
命令来重写缓存程序,重写之后的程序正如代码清单 12-2 所示。
代码清单 12-2 重写之后的缓存程序:/expire/volatile_cache.py
- class VolatileCache:
- def __init__(self, client):
- self.client = client
- def set(self, key, value, timeout):
- """
- 把数据缓存到键 key 里面,并为其设置过期时间。
- 如果键 key 已经有值,那么使用新值去覆盖旧值。
- """
- self.client.set(key, value, ex=timeout)
- def get(self, key):
- """
- 获取键 key 储存的缓存数据。
- 如果键不存在,又或者缓存已经过期,那么返回 None 。
- """
- return self.client.get(key)
重写之后的缓存程序实现是“安全的”:设置缓存和设置生存时间这两个操作要么就一起成功,要么就一起失败,“设置缓存成功了,但是设置生存时间却失败了”这样的情况将不会出现。后续的章节也会介绍如何通过 Redis 的事务功能来保证执行多条命令时的安全性。
其他信息
属性 | 值 |
---|---|
复杂度 | O(1) |
版本要求 | 带有 EX 选项和 PX 选项的 SET 命令从 Redis 2.6.12 版本开始可用。 |