我想了解redis-py
版本3.5.3访问数据库Redis的指令multi()
和watch()
的正确用法。Redis服务器版本为Redis server v=5.0.5。
特别是,我编写并执行了以下代码,其中使用了指令watch
,并在键keyWatch
上使用:
r = redis.Redis()
def key_incr():
print('keyWatch before incr = ' + r.get('keyWatch').decode("utf-8"))
pipe = r.pipeline()
pipe.watch('keyWatch')
pipe.multi()
pipe.incr('keyWatch')
pipe.execute()
print('keyWatch after incr = ' + r.get('keyWatch').decode("utf-8"))
key_incr()
前面的代码可以正确执行,其输出为(keyWatch
的初始值为9
):
keyWatch before incr = 9
keyWatch after incr = 10
如果我从代码中删除指令multi()
,它将变为:
r = redis.Redis()
def key_incr():
print('keyWatch before incr = ' + r.get('keyWatch').decode("utf-8"))
pipe = r.pipeline()
pipe.watch('keyWatch')
# NOTE: here the multi() instruction is commented
#pipe.multi()
pipe.incr('keyWatch')
pipe.execute()
print('keyWatch after incr = ' + r.get('keyWatch').decode("utf-8"))
key_incr()
它的执行会引发以下异常:
raise WatchError("Watched variable changed.")
redis.exceptions.WatchError: Watched variable changed.
我的需要是避免其他客户端在事务内部修改密钥keyWatch
,但为什么在我的示例代码中,只有当multi()
指令不存在时才会引发WatchError
异常?
谢谢
编辑
通过redis-cli monitor
(在文章的其余部分中为MONITOR),我可以看到在执行前两段代码期间对服务器的请求。
对于multi()
指令的情况,我有以下请求:
> redis-cli monitor
OK
1681733993.273545 [0 127.0.0.1:46342] "GET" "keyWatch"
1681733993.273790 [0 127.0.0.1:46342] "WATCH" "keyWatch"
1681733993.273934 [0 127.0.0.1:46342] "MULTI"
1681733993.273945 [0 127.0.0.1:46342] "INCRBY" "keyWatch" "1"
1681733993.273950 [0 127.0.0.1:46342] "EXEC"
1681733993.274279 [0 127.0.0.1:46342] "GET" "keyWatch"
对于没有multi()
指令的情况,我有以下请求:
> redis-cli monitor
OK
1681737498.462228 [0 127.0.0.1:46368] "GET" "keyWatch"
1681737498.462500 [0 127.0.0.1:46368] "WATCH" "keyWatch"
1681737498.462663 [0 127.0.0.1:46368] "INCRBY" "keyWatch" "1"
1681737498.463072 [0 127.0.0.1:46368] "MULTI"
1681737498.463081 [0 127.0.0.1:46368] "EXEC"
在第二种情况下,也存在MULTI
指令,但在它和EXEC
之间没有任何请求。keyWatch
异常是由EXEC
指令引发的,实际上MONITOR没有显示最后一个"GET" "keyWatch"
请求(与第一个MONITOR日志比较,可以找到最后一个"GET" "keyWatch"
请求)。
所有这些都表明异常是由执行以下命令引起的:"INCRBY" "keyWatch" "1"
在块MULTI/EXEC
之外。
如果有人能证实这一点,并解释更好的行为是赞赏。
谢谢
1条答案
按热度按时间j2cgzkjk1#
WATCH、MULTI和EXEC被设计为一起工作。具体来说,对MULTI和EXEC的调用允许隔离地执行排队的命令。Redis称之为transaction。
它是这样工作的:
当这些命令正在排队时,其他命令可能会进入。这些其他命令可能会更改事务的一部分密钥,这可能是错误的。请输入WATCH。
WATCH用于监视这些键。如果在调用EXEC时它们已被更改,EXEC将返回错误。然后您需要运行代码重试事务(或者可能生成错误,具体取决于您的需要)。
如果它们没有被改变,那么EXEC执行所有排队的命令,生命继续。
它的工作原理是这样的:
请注意,您不必像上面的例子所示的那样在事务中监视密钥。在这种情况下,我不在乎是否有人更改了我要删除的内容。
Redis中的事务并不是开发人员通常认为的那样。如果你想更深入地了解细节,Redis网站上有一个guide to transactions。