zoukankan      html  css  js  c++  java
  • redis的事务

        

    MULTI/EXEC等命令实现事务

          传统关系型数据库的事务相信大家都很熟悉了,但作为流行的非关系型数据库,redis本身也是支持事务的。

    其中,MULTI,EXEC,DISCARD和WATCH等命令是Redis中事务的基础。

    它们允许一步执行一组命令,并具有两个重要保证:

    • 事务中的所有命令都被序列化并顺序执行。

      在 Redis事务的执行过程中,永远不会发生另一个客户端发出的请求。这样可以确保将命令作为单个隔离操作执行。

    • 所有命令都将被处理,或者不处理任何命令,因此Redis事务也是原子的。(注意,这里只是保证执行,后面会提到

    好,接下来我们来看一看官方给出的一个例子:

    > MULTI
    OK
    > INCR foo
    QUEUED
    > INCR bar
    QUEUED
    > EXEC
    1) (integer) 1
    2) (integer) 1

          上面的例子,先用multi开启事务,该命令响应OK。

           此时,用户可以发出多个命令。Redis不会执行这些命令,而是将它们排队。一旦调用EXEC,将执行所有命令。

           若将上面的EXEC替换为DISCARD,redis将刷新事务队列并退出事务,并不执行。

           那么,这时候问题来了,如果执行事务期间发生错误会怎样呢?

    有两种情况:

    1、如果多个命令能不能通过语义检查,服务器将记住命令累积期间发生的错    误,并且将拒绝执行事务,并不会执行EXEC命令。并且在EXEC期间还会返回错误并自动丢弃该事务(指Redis 2.6.5版本之后)。

    2、 EXEC 之后发生的错误不会以特殊方式处理:即使在事务期间某些命令失败,也会执行所有其他命令。即使命令失败,队列中的所有其他命令也会得到处理       

          这是很重要的一点,是不是跟我们常见的事务有所不同?事务应该保证所有操作要么全部成功,要么全部失败,其中一个失败时应该进行回滚才对,但redis并没有。

    LUA脚本保证百分百原址回迁 预计租金每年增3亿元

    接下来,我们再看redis的另一种事务实现:lua脚本

    从2.6.0版开始,EVAL和EVALSHA命令可用于执行Lua脚本。

             先来一个例子:

    > eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"

          lua脚本的编写也很简单,那么对比multi命令,它们的区别在于:

    (1)redis事务是基于乐观锁,lua脚本是基于redis的单线程执行命令。
    (2)redis事务的执行原理就是一次命令的批量执行,而lua脚本可以加入自定义逻辑。

           当然,它们也有相同的地方:很好的实现了一致性、隔离性和持久性,但没有实现原子性,无论是redis事务,还是lua脚本,如果执行期间出现运行错误,之前的执行过的命令是不会回滚的。

     

    为什么redis不支持回滚?

             以下为官方解释:

            如果您具有关系数据库背景,则Redis命令在事务期间可能会失败,但Redis仍会执行事务的其余部分而不是回滚,这一事实对您来说可能很奇怪。

    但是,对于此行为有好的意见:

    • 仅当使用错误的语法(并且在命令队列期间无法检测到该问题)或针对持有错误数据类型的键调用Redis命令时,该命令才能失败:这实际上意味着失败的命令是编程错误的结果,还有一种很可能在开发过程中而不是生产过程中发现的错误。

    • Redis在内部得到了简化和加快,因为它不需要回滚的能力。

           简单的说,官方认为只有开发者犯错时,才会出现需要回滚的情况(这种情况无法避免但应该有开发者负责,自己的锅自己背)

           

           其次,并且Redis命令失败所需的错误类型不太可能进入生产环境,因此redis选择了不支持错误回滚的更简单,更快捷的方法。

  • 相关阅读:
    hiho #1502:最大子矩阵(元素和不超过k)
    IPC 进程间通信方式——消息队列
    IPC 进程间通信方式——共享内存
    IPC 进程间通信方式——管道
    hiho #1032: 最长回文子串
    TCP超时与重传机制与拥塞避免
    C++关于构造函数 和 析构函数 能否抛出异常的讨论
    基于TCP的客户端、服务器端socket编程
    hiho #1043 : 完全背包
    hiho #1485 : hiho字符串(滑动窗口)
  • 原文地址:https://www.cnblogs.com/yansum/p/11920652.html
Copyright © 2011-2022 走看看