首页 > 解决方案 > redis中如何根据key的存在设置hash key过期时间

问题描述

我想设置一些哈希键的过期时间,如果是第一次设置密钥,我希望设置一个过期时间,否则我更喜欢保持第一次设置的过期时间。

由于有大量的哈希键,我更喜欢在管道中进行,但是下面的函数效果不佳。

该行pipe.exists(hkey)返回一个管道的 obj,它始终为 True,因此无论哈希键是否存在,if 子句总是转到一个部分。

我的问题是:有没有一种方法可以根据带有管道的哈希键的存在来设置哈希键的到期?

def test1(hkey, v):
    with r.pipeline() as pipe:
        # tmp = pipe.exists(hkey)
        # pipe.exists(hkey) is a pipe obj, which is always True, 
        # this line not work as expected and the two lines below it will never be excuted.
        if not pipe.exists(hkey):
            pipe.hset(hkey, v, v)
            pipe.expire(hkey, 3600)
        else:
            # no matter whether the hash key is exist or not, the if else statment always goes to this line.
            pipe.hset(hkey, v, v)
        pipe.execute()

标签: pythonredis

解决方案


您无法使用管道实现这一点,因为在整个管道执行之前您永远不知道密钥是否存在。相反,您可以使用Lua 脚本来完成这项工作:

local key = KEYS[1]
local field = ARGV[1]
local value = ARGV[2]
local ttl = ARGV[3]

local exist = redis.call('exists', key)

redis.call('hset', key, field, value)

if exist == 0 then
    redis.call('expire', key, ttl)
end

检查这个以了解如何使用 redis-py 运行 Lua 脚本。然后使用管道运行脚本以减少RTT.

更新

如果你坚持使用WATCH来做这项工作,你可以试试下面的代码:

with r.pipeline() as pipe:
    while 1:
        try:
            pipe.watch(hkey)

            exist = pipe.exists(hkey)

            pipe.multi()

            if not exist:
                pipe.hset(hkey, v, v)
                pipe.expire(hkey, 3600)
            else:
                pipe.hset(hkey, v, v)

            pipe.execute()
            break;
        except WatchError:
            continue

推荐阅读