如何在Redis中实现带回滚的事务

Tom*_*mmy 6 java database transactions redis

我的程序需要将数据作为一个事务添加到Redis中的两个列表中。两个列表中的数据应该一致。如果出现异常或系统故障,因此程序只将数据添加到一个列表中,系统应该能够恢复和回滚。但是基于Redis doc,它不支持回滚。我该如何实施?我使用的语言是Java。

The*_*ill 7

如果您需要事务回滚,我建议使用 Redis 以外的其他东西。Redis 事务与其他数据存储不同。即使 Multi/Exec 也不能满足您的需求 - 首先是因为没有回滚。如果您想要回滚,您将不得不拉下两个列表,以便您可以恢复 - 并希望在我们的错误条件和“回滚”之间没有其他客户端也修改了任何一个列表。以一种理智而可靠的方式做到这一点并非微不足道,也不简单。这对 SO 来说也可能不是一个好问题,因为它非常广泛,而不是特定于 Redis。

现在至于为什么 EXEC 不按照人们的想法行事。在您提出的方案中,MULTI/EXEC处理以下情况:

  1. 您设置 WATCH 以确保没有其他更改发生
  2. 您的客户在发出 EXEC 之前就死了
  3. Redis 内存不足

由于发出 EXEC 命令,完全有可能出现错误。当您发出 EXEC 时,Redis 将执行队列中的所有命令并返回错误列表。它不会提供 add-to-list-1 工作和 add-to-list-2 失败的情况。您的两个列表仍然会不同步。当您发出时,在发出 MULTI 后说 LPUSH,OK除非您:

  • a) 之前添加了一个手表并且该列表中的某些内容已更改或
  • b) Redis 响应队列推送命令返回 OOM 条件

DISCARD 不像某些人想象的那样工作。DISCARD 用于代替EXEC,而不是作为回滚机制。一旦您发出 EXEC,您的交易就完成了。Redis 根本没有任何回滚机制——这不是 Redis 的事务。

理解 Redis 所谓的事务的关键是要意识到它们本质上是客户端连接级别的命令队列。它们不是数据库状态机。


Kar*_*all 5

Redis 事务是不同的。它保证了两件事。

  1. 执行所有命令或不执行任何命令
  2. 连续和不间断的命令

话虽如此,如果您可以控制代码并知道系统故障何时发生(某种捕获异常),您可以通过这种方式实现您的要求。

  1. MULTI -> 开始交易
  2. LPUSH queue1 1 -> 推入队列1
  3. LPUSH queue2 1 -> 推入队列2
  4. 执行/丢弃

在第 4 步中,如果没有错误,请执行 EXEC,如果遇到错误或异常,并且想要回滚,请执行 DISCARD。

希望这是有道理的。