【问题标题】:Redis, only allow operation on existing keysRedis,只允许对现有键进行操作
【发布时间】:2012-06-11 20:59:11
【问题描述】:

我正在使用python包(redis-py)来操作redis数据库。我有一堆客户端在 redis 中设置哈希的键和值。我希望他们仅在散列存在时设置键和值。如果散列不存在,设置键和值将创建散列,这不是我想要做的。

在redis-py页面(https://github.com/andymccurdy/redis-py)中,作者提出了一种在客户端进行原子操作的方法。于是我写了一个类似的函数:

    with r.pipeline() as pipe:
        while True:
            try:
                pipe.watch("a_hash")
                if pipe.exists("a_hash"):
                    pipe.hset("a_hash", "key", "value")                  
                break
            except redis.WatchError:
                continue
            finally:
                pipe.reset()

但是,这似乎不起作用。在我从另一个客户端删除哈希后,这个哈希仍然是由这段代码创建的,所以我猜这段代码不是原子操作。有人可以帮我确定这段代码有什么问题吗?还是有更好的方法来达到这个目的?

感谢您的帮助!

【问题讨论】:

    标签: python redis atomic


    【解决方案1】:

    我建议阅读Redis documentation 中解释的 WATCH/MULTI/EXEC 块的定义。

    在这样的块中,只有 MULTI 和 EXEC 之间的命令实际上是原子处理的(并且有条件地,根据手表的全有或全无语义)。

    在您的示例中,EXISTS 和 HSET 命令不是原子执行的。实际上,您不需要这种原子性:您想要的是条件执行。

    这应该会更好:

    with r.pipeline() as pipe:
        while True:
            try:
                pipe.watch("a_hash")
                if pipe.exists("a_hash"):
                    pipe.multi()
                    pipe.hset("a_hash", "key", "value")
                    pipe.execute()
                break
            except redis.WatchError:
                continue
            finally:
                pipe.reset()
    

    如果密钥在 EXISTS 之后 MULTI 之前被删除,HSET 将不会被执行,感谢 watch。

    使用 Redis 2.6,Lua server-side script 可能更容易编写,也更高效。

    【讨论】:

    • 谢谢迪迪埃。还有一个问题,如果在multi之后删除了key怎么办?既然redis在multi之后是对命令进行排队,那么这种情况下hset还执行吗?
    • 如果在 MULTI 和 HSET 之间甚至 HSET 和 EXEC 之间删除了密钥,则 MULTI/EXEC 块被中止,并且 HSET 不应用。
    • 这个例子需要reset()吗?文档说:“如果管道被用作上下文管理器,reset() 将被自动调用。”
    • 它会被自动调用——我还是更喜欢让它显式。
    猜你喜欢
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 2016-10-08
    • 2021-05-25
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多