【问题标题】:How to implement transaction with rollback in Redis如何在 Redis 中实现事务回滚
【发布时间】:2017-01-27 21:28:33
【问题描述】:

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

【问题讨论】:

    标签: java database transactions redis


    【解决方案1】:

    如果你需要事务回滚,我推荐使用 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 所谓的事务的关键是要认识到它们本质上是客户端连接级别的命令队列。它们不是数据库状态机。

    【讨论】:

    • 有意思,如果redis不能回滚,为什么它声称它的事务是原子的?
    【解决方案2】:

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

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

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

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

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

    希望这是有道理的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-24
      • 2021-02-22
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多