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选择了不支持错误回滚的更简单,更快捷的方法。

 

posted @ 2019-11-23 22:52  yansum  阅读(392)  评论(0编辑  收藏  举报