Redis - 事务

Redis 中的事务是一组命令的集合。事务同命令一样都是 Redis 的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的应用非常普遍,如银行转账过程中 A 给 B 汇款,首先系统从 A 的账户将钱划走,然后向 B 的账户增加相应的金额。这两个不走必须属于同一个事务,要么全都执行要么全都不执行。否则只执行第一步,钱就凭空消失了,这显然无法让人接受。

事务的原理是先将属于同一个事务的命令发送给 Redis,然后再让 Redis 依次执行这些命令。例如:

127.0.0.1:6379> MSET bank:A:account 500 bank:B:account 500
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY bank:A:account 100
QUEUED
127.0.0.1:6379> INCRBY bank:B:account 100
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 400
2) (integer) 600

上面的代码演示了事务的使用方式。首先使用 MULTI 命令告诉 Redis:“下面我发给你的命令属于同一个事务,你先不要执行,而是把它们暂时存起来。” Redis 回答:“OK。”

而后我们发送了 DECRBY 和 INCRBY 命令来实现 A 账户向 B 账户汇款的操作,可以看到 Redis 遵守了承诺,没有执行这些命令,而是用 QUEUED 表示这两条命令已经进入等待执行的事务队列中了。

当把所有要在同一事务中执行的命令都发给了 Redis 后,我们使用 EXEC 命令告诉 Redis 将等待执行的事务队列中的所有命令(即所有返回 QUEUED 的命令)按照发送顺序依次执行。EXEC 命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。

Redis 保证了一个事务中的所有命令要么都执行,要么都不执行。如果在发送 EXEC 命令前客户端断线了,则 Redis 会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了 EXEC 命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为 Redis 中已经记录了所有要执行的命令。

除此之外,Redis 的事务还能保证一个事务内的命令一次执行而不被其他命令插入。试想客户端 A 需要执行几条命令,同时客户端 B 发送了一条命令,如果不使用事务,则客户端 B 的命令可能会插入到客户端 A 的几条命令中执行。如果不希望发送这种情况,也可以使用事务。

 

错误处理

如果一个事务中的某个命令执行出错,Redis 会怎样处理呢?要回答这个问题,首先需要知道什么原因会导致命令执行出错。

语法错误

语法错误指命令不存在或者命令参数的个数不对。比如:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key value
QUEUED
127.0.0.1:6379> SET key
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> ERRORCOMMAND key
(error) ERR unknown command 'ERRORCOMMAND'
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

跟在 MULTI 命令后执行了 3 个命令:一个是正确的命令,成功地加入事务队列:其余两个命令都有语法错误。而只要有一个命令有语法错误,执行 EXEC 命令后 Redis 就会直接返回错误,连语法正确的命令也不会执行。

版本差异:Redis 2.6.5 之前的版本会忽略有语法错误的命令,然后执行事务中其他语法正确的命令。

运行错误

运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行前 Redis 是无法发现错误的,所以在事务里这样的命令会被 Redis 接受并执行。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令),示例如下:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key 1
QUEUED
127.0.0.1:6379> SADD key 2
QUEUED
127.0.0.1:6379> SET key 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> GET key
"3"

可见虽然 SADD key 2 出现了错误,但是 SET key 3 依然执行了。

 

WATCH 命令

WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会被执行。监控一直持续到 EXEC 命令(事务中的命令是在 EXEC 之后才执行的,所以在 MULTI 命令后可以修改 WATCH 监控的键值),如:

127.0.0.1:6379> SET key 1
OK
127.0.0.1:6379> WATCH key
OK
127.0.0.1:6379> SET key 2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key 3
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET key
"2"
127.0.0.1:6379> 
127.0.0.1:6379> SET key 1
OK
127.0.0.1:6379> WATCH key
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
127.0.0.1:6379> GET key
"3"

执行 EXEC 命令后会取消对所有键值的监控,如果不想执行事务中的命令也可以使用 UNWATCH 命令来取消对所有键的监控。

 

More: http://www.redis.io/topics/transactions

posted on 2016-07-10 20:17  huey2672  阅读(229)  评论(0编辑  收藏  举报