能否按照"The Little Redis Book"的例子向我解释一下:
使用上面的代码,我们将无法实现自己的incr命令,因为一旦调用了exec,它们就会一起执行.从代码中,我们做不到:
redis.multi()
current = redis.get('powerlevel')
redis.set('powerlevel', current + 1)
redis.exec()
Run Code Online (Sandbox Code Playgroud)
这不是Redis交易的工作方式.但是,如果我们为powerlevel添加一个手表,我们可以这样做:
redis.watch('powerlevel')
current = redis.get('powerlevel')
redis.multi()
redis.set('powerlevel', current + 1)
redis.exec()
Run Code Online (Sandbox Code Playgroud)
如果另一个客户端在我们调用了watch之后更改了powerlevel的值,那么我们的事务将会失败.如果没有客户端更改该值,则该集合将起作用.我们可以在循环中执行此代码,直到它工作.
为什么我们不能在不能被其他命令中断的事务中执行增量?为什么我们需要迭代而等到交易开始前没有人改变价值?
Did*_*zia 76
这里有几个问题.
1)为什么我们不能在不能被其他命令中断的事务中执行增量?
请注意,首先Redis"交易"与大多数人认为交易在经典DBMS中的完全不同.
# Does not work
redis.multi()
current = redis.get('powerlevel')
redis.set('powerlevel', current + 1)
redis.exec()
Run Code Online (Sandbox Code Playgroud)
您需要了解在服务器端执行的操作(在Redis中)以及在客户端(在脚本中)执行的操作.在上面的代码中,GET和SET命令将在Redis端执行,但是应该在客户端执行当前的分配和当前+ 1的计算.
为了保证原子性,MULTI/EXEC块会将Redis命令的执行延迟到执行程序.因此客户端只会在内存中堆积GET和SET命令,并在最后一次执行它们并原子地执行它们.当然,尝试将电流分配给GET和增量的结果将很快发生.实际上,redis.get方法只返回字符串"QUEUED"以表示命令被延迟,并且增量将不起作用.
在MULTI/EXEC块中,您只能使用在块开始之前可以完全了解其参数的命令.您可能需要阅读文档以获取更多信息.
2)为什么我们需要迭代而等到交易开始之前没有人改变价值?
这是并发乐观模式的一个例子.
如果我们没有使用WATCH/MULTI/EXEC,我们就会遇到潜在的竞争条件:
# Initial arbitrary value
powerlevel = 10
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: SET powerlevel 11
session B: SET powerlevel 11
# In the end we have 11 instead of 12 -> wrong
Run Code Online (Sandbox Code Playgroud)
现在让我们添加一个WATCH/MULTI/EXEC块.使用WATCH子句,仅当值未更改时,才会执行MULTI和EXEC之间的命令.
# Initial arbitrary value
powerlevel = 10
session A: WATCH powerlevel
session B: WATCH powerlevel
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: MULTI
session B: MULTI
session A: SET powerlevel 11 -> QUEUED
session B: SET powerlevel 11 -> QUEUED
session A: EXEC -> success! powerlevel is now 11
session B: EXEC -> failure, because powerlevel has changed and was watched
# In the end, we have 11, and session B knows it has to attempt the transaction again
# Hopefully, it will work fine this time.
Run Code Online (Sandbox Code Playgroud)
所以你不必迭代等到没有人改变值,而是一次又一次地尝试操作,直到Redis确定值是一致的并且表示它是成功的.
在大多数情况下,如果"交易"足够快并且争用的可能性很低,则更新非常有效.现在,如果存在争用,则必须对某些"事务"执行一些额外的操作(由于迭代和重试).但数据始终是一致的,不需要锁定.