当前位置: 首页 > 面试题库 >

Redis中的交易和观察声明

武元白
2023-03-14
问题内容

您能否以“ The Little Redis Book”中的示例为例向我解释一下:

使用上面的代码,我们将无法实现自己的incr命令,因为一旦exec被调用,它们就会一起执行。从代码中,我们不能:

redis.multi() 
current = redis.get('powerlevel') 
redis.set('powerlevel', current + 1) 
redis.exec()

这不是Redis事务的工作方式。但是,如果我们向powerlevel添加手表,则可以执行以下操作:

redis.watch('powerlevel') 
current = redis.get('powerlevel') 
redis.multi() 
redis.set('powerlevel', current + 1) 
redis.exec()

如果另一个客户在我们对其进行监视之后更改了powerlevel的值,则我们的交易将失败。如果没有客户端更改该值,则该设置将起作用。我们可以循环执行此代码,直到工作为止。

为什么我们不能在不能被其他命令中断的事务中执行增量?为什么我们需要进行迭代并等待直到没有人更改值 开始事务?


问题答案:

这里有几个问题。

1)为什么我们不能在不能被其他命令中断的事务中执行增量?

首先请注意,Redis的“事务”与大多数人认为经典DBMS中的事务完全不同。

# Does not work
redis.multi() 
current = redis.get('powerlevel') 
redis.set('powerlevel', current + 1) 
redis.exec()

您需要了解在服务器端执行的操作(在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

现在,让我们添加一个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.

因此,您不必反复等待直到没有人更改该值,而是一次又一次尝试该操作,直到Redis确保值一致并发出成功信号。

在大多数情况下,如果“事务”足够快并且发生争用的可能性很低,则更新非常有效。现在,如果存在争用,则必须对某些“事务”执行一些额外的操作(由于迭代和重试)。但是数据将始终保持一致,并且不需要锁定。



 类似资料:
  • 问题内容: 我试图使声明式交易工作。 这是我的spring.xml文件: 这是我的控制器实现: 两者都在称为test的包中。 这是我的尝试: 但这引发了异常: org.hibernate.HibernateException:如果没有活动事务,createQuery无效 为什么transactionManager不起作用?我希望使用@Transactional批注将所有事务由Spring框架管理。

  • 问题内容: 当我们在Redis中使用事务时,它基本上流水线化了事务中的所有命令。当EXEC被触发时,所有命令将一起执行,从而始终保持多个命令的原子性。 这与流水线不一样吗? 流水线和事务有何不同?另外,为什么Redis的单线程性质不足以满足要求?为什么我们明确需要流水线/事务? 问题答案: 流水线主要是网络优化。从本质上讲,这意味着客户端可以缓冲一堆命令并将它们一次性发送到服务器。不能保证在事务中

  • 我来自同步编程背景,我很难理解可观察性。 这是我的服务/提供商的摘录(离子2项目) 我将从订阅它。关于这一点,我有几个问题。 > 即使我没有声明,上面的代码是否返回一个可观察/观察者? 响应是JSON。如何检查/处理JSON并执行一些操作,如 那就做吧 我认为应该在提供者类中完成。只是一个典型的提示/例子将是真棒。 当请求到达subscribe方法时,它是否真的发生了? 创建和返回Angular

  • 我试图理解当我使用 在或之后,在我使用时返回true 我知道是一次性的。isDisposed()返回false。有人能解释一下到底发生了什么吗?。我理解一个写得很好的观察。create不能在onComplete()或onError()之后发出项。

  • 我有两个演员,父母和孩子。家长使用内容监视孩子。看(孩子)。如果孩子调用上下文。停止(自我)父级收到终止消息。但是,如果子级抛出异常,akka将重新启动该异常,但不会向父级发送终止消息。 家长参与者如何监视孩子并监视任何终止/重新启动? 我提出的一个选项是覆盖父级中的主管策略,以便在出现任何异常时停止: 据我所知,这将适用于这位演员的所有孩子。理想情况下,我希望对个别孩子(演员类型)有一个不同的监

  • 问题内容: 我一直在阅读Observer模式,以保持UI处于最新状态,但仍然看不到它的用途。即使在我的特定对象中通知了我的MainActivity然后运行update();方法我仍然无法使用Pet对象来获取更新值,因为该对象是在Oncreate中创建的…而我只是无法创建新对象,因为那时变量会有所不同..这是我的实施,它似乎不起作用。 观察者/ MainActivity 可观察/宠物 问题答案: 首