我试图了解指令
multi()
和watch()
的正确使用,以通过redis-py
版本3.5.3访问数据库Redis。 Redis 服务器的版本是 Redis 服务器 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
,但为什么在我的示例代码中,仅当WatchError
指令不存在时才会引发multi()
异常?
谢谢
在这里我编辑我的问题并添加一些我通过使用命令监视器发现的内容
通过
redis-cli monitor
(帖子其余部分中的 MONITOR)我可以在执行前 2 个代码片段期间看到对服务器的请求。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
如果有人可以确认这一点并更好地解释这种行为,我们将不胜感激。
谢谢
WATCH、MULTI 和 EXEC 旨在协同工作。具体来说,对 MULTI 和 EXEC 的调用允许隔离执行排队的命令。 Redis 将此称为事务。
其工作原理如下:
MULTI <- start queueing commands
INCR someKey <- queue this command
SET someOtherKey someValue <- queue this command
UNLINK someThirdKey <- queue this command
EXEC <- execute all the queued commands
当这些命令正在排队时,其他命令可能会进来。这些其他命令可能会更改属于事务一部分的密钥,这可能会很糟糕。进入观看。
WATCH 用于观察这些按键。如果在调用 EXEC 时它们已更改,则 EXEC 将返回错误。然后,您需要运行代码来重试事务(或者可能会生成错误,具体取决于您的需要)。
如果它们没有更改,则 EXEC 执行所有排队的命令,然后生活继续。
它的工作原理如下:
WATCH someKey someOtherKey <- watch these for changes
MULTI <- start queueing commands
INCR someKey <- queue this command
SET someOtherKey someValue <- queue this command
UNLINK someThirdKey <- queue this command
EXEC <- either error or execute queued commands
请注意,您不有将密钥作为交易的一部分进行观察,如我上面的示例所示。在这种情况下,我不在乎是否有人更改了我要删除的内容。
Redis 中的事务并不是开发人员通常认为的那样。如果您想更深入地了解详细信息,Redis 网站上有一个交易指南。