您的位置:首页 > 数据库 > Redis

redis中的事务

2015-11-29 21:22 651 查看
本篇博客来讨论redis的事务。redis通过MULTI,EXEC,DISCARD以及WATCH命令来实现事务机制的。

MULTI…EXEC

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

事务中的所有命令,要么依次全部执行,要么都不执行。

在执行事务中的命令时,来自其它客户端的命令不会穿插执行。redis的事务是原子级的,支持并发的。

来看一些示例代码

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SADD set1 a b c
QUEUED
127.0.0.1:6379> SADD set1 d
QUEUED
127.0.0.1:6379> SADD set1 e
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 3
2) (integer) 1
3) (integer) 1
127.0.0.1:6379> SMEMBERS set1
1) "a"
2) "d"
3) "c"
4) "b"
5) "e"


DISCARD命令

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

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SADD set1 x
QUEUED
127.0.0.1:6379> DISCARD
OK


事务中的错误处理

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

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SADD set1 x
QUEUED
127.0.0.1:6379> SMEMBERS
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> SMEMBERS set1
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors


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

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SREM set1 d
QUEUED
127.0.0.1:6379> LPUSH set1 d
QUEUED
127.0.0.1:6379> SADD set1 m
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) (integer) 1
127.0.0.1:6379> SMEMBERS set1
1) "a"
2) "m"
3) "c"
4) "e"
5) "b"


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

为什么不支持roll back?

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

事务中的错误,几乎都会出现在开发中,而不是生产中,所以,这些错误都会在开发调试的过程中被程序员修复。即便有些错误带到了生产中,回滚并不能弥补程序员的错误。

redis更加重视简单性和性能。

WATCH命令

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

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

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

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC


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

当EXEC命令执行后,不管成功与否,被监控的键都会释放监控。也可以通过UNWATCH命令来手动解除对某个键的监控。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息