redis中的事务

来源:互联网 发布:广州市失独数据 编辑:程序博客网 时间:2024/05/22 02:09

本篇博客来讨论redis的事务。redis通过MULTI,EXEC,DISCARD以及WATCH命令来实现事务机制的。

MULTI…EXEC

redis客户端通过MULTI命令来通知redis服务器即将进入事务模式,redis服务器端返回OK。然后redis客户端开始发送命令,redis服务器接收到命令后,不会立即执行,而是先加入事务队列中并返回QUEUED,当redis客户端发送EXEC命令时,redis开始依次执行事务队列中的所有命令,并依次返回每条命令的结果。redis中的事务可以保证两点:

  1. 事务中的所有命令,要么依次全部执行,要么都不执行。
  2. 在执行事务中的命令时,来自其它客户端的命令不会穿插执行。redis的事务是原子级的,支持并发的。

来看一些示例代码

127.0.0.1:6379> MULTI OK127.0.0.1:6379> SADD set1 a b cQUEUED127.0.0.1:6379> SADD set1 dQUEUED127.0.0.1:6379> SADD set1 eQUEUED127.0.0.1:6379> EXEC1) (integer) 32) (integer) 13) (integer) 1127.0.0.1:6379> SMEMBERS set11) "a"2) "d"3) "c"4) "b"5) "e"

DISCARD命令

redis通过DISCARD命令来清空事务的命令队列并退出事务模式。

127.0.0.1:6379> MULTIOK127.0.0.1:6379> SADD set1 xQUEUED127.0.0.1:6379> DISCARDOK

事务中的错误处理

在redis的事务中,我们可能会遇到两种类型的错误,第一种是命令的语法错误,redis接收到这种命令后,会直接返回错误信息,并且当发送EXEC命令时,也不会执行其它命令,而是返回错误信息。第二种错误是语法正确,但操作的键的类型不对,redis接收到这种命令后,会返回QUEUED,在执行时,其它的命令正常执行,但这一条错误的命令会返回错误消息。下面我们来做个实验,首先看第一种错误

127.0.0.1:6379> MULTIOK127.0.0.1:6379> SADD set1 xQUEUED127.0.0.1:6379> SMEMBERS(error) ERR wrong number of arguments for 'smembers' command127.0.0.1:6379> SMEMBERS set1QUEUED127.0.0.1:6379> EXEC(error) EXECABORT Transaction discarded because of previous errors

只要事务中包含一个语法错误的命令,所有的命令都不会执行。再来看第二种情况

127.0.0.1:6379> MULTIOK127.0.0.1:6379> SREM set1 dQUEUED127.0.0.1:6379> LPUSH set1 dQUEUED127.0.0.1:6379> SADD set1 mQUEUED127.0.0.1:6379> EXEC1) (integer) 12) (error) WRONGTYPE Operation against a key holding the wrong kind of value3) (integer) 1127.0.0.1:6379> SMEMBERS set11) "a"2) "m"3) "c"4) "e"5) "b"

我们可以看到,LPUSH set1 d这个命令,很显然LPUSH只能对一个列表进行操作,而set1是集合类型,但redis在执行之前并不能分辨出来,所以当时返回的是QUEUED,但是在执行时,还是返回了错误消息。需要注意的是,其它命令都正常执行了。

为什么不支持roll back?

看到这里,如果你有关系型数据库的编程经验的话,你可能会很奇怪,为什么redis不支持回滚操作呢?官方文档的解释大概是这样的:

  1. 事务中的错误,几乎都会出现在开发中,而不是生产中,所以,这些错误都会在开发调试的过程中被程序员修复。即便有些错误带到了生产中,回滚并不能弥补程序员的错误。
  2. redis更加重视简单性和性能。

WATCH命令

先来考虑一下INCR这个命令,它是先读取(get)一个键的值,然后加一,再存储起来(set)。如果不使用INCR命令而自己实现的话,这个逻辑在并发的条件下可能会出现问题。WATCH命令可以很好地解决这个问题。

WATCH命令的原理是,监控一个或多个键,如果有任何一个被监控的键发生了变化,则EXEC命令失败。

我们来看下面的示例代码(伪代码)

WATCH mykeyval = GET mykeyval = val + 1MULTISET mykey $valEXEC

如果有多个客户端同时执行上面的代码,只有一个EXEC命令能够执行成功,因为MULTI…EXEC..属于事务,多个客户端不可能同时执行事务,肯定有一个先后顺序,当第一个事务的EXEC命令执行成功后,mykey就被修改了,其它事务的EXEC命令就会返回错误,所以,上面的代码是支持并发的。

当EXEC命令执行后,不管成功与否,被监控的键都会释放监控。也可以通过UNWATCH命令来手动解除对某个键的监控。

0 0
原创粉丝点击