Redis中的Multi和Pipleline都可以一次性执行多个命令,但是Pipeline只是把多个redis指令一起发出去,redis并没有保证这些指令执行的顺序,且减少了多次网络传递的开销,因而其执行效率很高;Multi相当于一个redis的transaction,保证整个操作的有序性,通过watch这些key,可以避免这些key在事务的执行过程中被其它的命令修改,从而导致得的到结果不是所期望的。
官方介绍MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令,事务可以一次执行多个命令,但是必须满足2个条件:
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。执行和是否成功是2个概念,并不是一个失败报错等,其他就失败。redis对事务是部分支持。如果最开始语法等就有提交错误,就相当于java的编译器都过不了,那么肯定全部不执行。如果在执行过程中报错,已经全部执行了,但是谁报错找谁,其他正常执行放行。各取所需!这里的事务并不是要么全部成功,要么全部失败,全部执行和全部成功(或者都失败)是2个概念。
二、命令介绍
MULTI:开启事务,总是返回OK
EXEC:提交事务
DISCARD:放弃事务(放弃提交执行)
WATCH:监控
QUEUED:将命令加入执行的队列
三、示例演示
1、开启事务
可以看到即使开了事务,事务中正确的命令也得到了执行,不正确的命令没有被执行,谁出错谁负责。
2、对部分命令增加watch
增加watch命令,可以确保被watch的key在事务的执行期间,如果被其它连接修改了,则当前事务则会在执行exec时报错,事务被中断,事务中所有的命令都不会执行。
1)对名为t1的key增加watch
127.0.0.1:6379> watch t1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set t1 t111
QUEUED
127.0.0.1:6379> set t2 v222
QUEUED
127.0.0.1:6379> set t3 v333
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get t1
“v111”
127.0.0.1:6379> get t2
“v2”
127.0.0.1:6379> get t3
“t33”
此时在事务的执行区间,即在执行了multi之后未执行exec之前,其它连接执行了修改t1的如下操作:
127.0.0.1:6379> set t1 v111
OK
在执行exec命令时就报了(nil)这样一个错误结果,表示当前事务执行失败。通过后续的get命令查看t1、t2和t3的值,只有t1的值发生了变化,是被其它连接修改了,当前事务中的命令都没有被执行。
2)对名为t2的key增加watch
127.0.0.1:6379> watch t2
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set t1 t111
QUEUED
127.0.0.1:6379> set t2 v222
QUEUED
127.0.0.1:6379> set t3 v333
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get t1
“v111”
127.0.0.1:6379> get t2
“v222”
127.0.0.1:6379> get t3
“t33”
127.0.0.1:6379> unwatch
OK
在事务区间,其它连接对t2进行了修改:
127.0.0.1:6379> set t2 v222
OK
当执行事务提交命令exec时,发现被watch的t2被修改了,当前事务执行失败,通过get命令查看,只有t2的值发生了变化,是被其它连接修改了的,当前事务全部命令都没有执行。
这两个增加对key进行watch的示例,演示了被watch的key可以是事务中的任意key,只要是被watch的key被修改,整个事务都不会执行。