Redis的事务可以一次性执行多条命令,本质是一组命令的集合,一个事务中的命令都会序列化,在执行的时候,会按顺序的串行执行,不允许加塞,不会被其他的命令插入。在一个事务的命令队列中,一次性,顺序性、排他性的执行一系列的命令。
Redis事务命令
MULTI
:标记一个事务块的开始。EXEC
:执行事务中所有在排队等待的指令并将链接状态恢复到正常,当使用WATCH时,只有当被监视的键没有被修改,且允许检查设定机制时,EXEC会被执行。DISCARD
:放弃事务,并且将连接状态恢复到正常。如果已使用WATCH,DISCARD将释放所有被WATCH的key。WATCH key [key ...]
:标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁check-and-set [CAS] )。如果被监视的key被其他的命令改动,那么事务将打断,不会执行成功。UNWATCH
:释放一个事务中已被监视的所有key。如果执行EXEC 或者DISCARD, 则不需要手动执行UNWATCH 。
事务正常执行
127.0.0.1:6379> MULTI # 标记事务开始
OK
127.0.0.1:6379> SET money 100 # 添加命令
QUEUED # 命令进入队列中等待执行
127.0.0.1:6379> SET name zhangsan
QUEUED
127.0.0.1:6379> SET gender male
QUEUED
127.0.0.1:6379> EXEC # 执行事务,三条命令顺序执行
1) OK
2) OK
3) OK
127.0.0.1:6379> KEYS *
1) "gender"
2) "money"
3) "name"
127.0.0.1:6379> GET name
"zhangsan"
放弃事务
127.0.0.1:6379> MULTI # 标记事务开始
OK
127.0.0.1:6379> SET name zhangsan # 添加命令
QUEUED # 命令进入队列中等待执行
127.0.0.1:6379> SET gender male
QUEUED
127.0.0.1:6379> DISCARD # 放弃事务
OK
127.0.0.1:6379> KEYS * # 可以看到,刚才队列中的命令并没有被执行
(empty list or set)
事务中语法错误
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET name zhangsan
QUEUED
127.0.0.1:6379> SET age 20
QUEUED
127.0.0.1:6379> asdas # 故意乱输命令
(error) ERR unknown command `asdas`, with args beginning with:
127.0.0.1:6379> SET gender male
QUEUED
127.0.0.1:6379> exec # 在执行事务的时候,抛出错误,并且其他正常的命令都没有执行成功
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> KEYS *
(empty list or set)
事务中命令执行失败
127.0.0.1:6379> SET name zhangsan # 在事务之前设置一个name值
OK
127.0.0.1:6379> MULTI # 开始事务
OK
127.0.0.1:6379> SET age 20
QUEUED
127.0.0.1:6379> INCRBY name 20 # 对name增加20
QUEUED
127.0.0.1:6379> SET address cd
QUEUED
127.0.0.1:6379> exec # 执行事务后,发现对name增加20的命令抛出错误,但是其余两条命令却执行成功了
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> GET age
"20"
在事务中,可能发生两种错误
- 语法错误:这种在命令放入队列之前就可以检测出来的错误,就会直接终止事务的继续,其他命令也将不会被执行成功。
- 执行失败:执行失败的命令,比如
INCR
命令,它只对数字的值生效,不然就会抛出错误,但是在命令入队的时候,是检测不出来的。所以事务中的其他命令依旧会执行成功。
监视
第一个客户端
127.0.0.1:6379> set money 200
OK
127.0.0.1:6379> WATCH money # 监视 money
OK
127.0.0.1:6379> MULTI # 开始事务
OK
127.0.0.1:6379> INCRBY money 20
QUEUED
127.0.0.1:6379> INCRBY money 20
QUEUED
127.0.0.1:6379> EXEC #执行事务
(nil)
第二个客户端
127.0.0.1:6379> SET money 300 # 在第一个客户端执行事务之前,第二个客户端修改了money的值,事务不会执行成功
OK
WATCH
指令,类似乐观锁,事务提交时,如果被监视的key已经在其他地方被修改,那么整个事务队列的命令都不会被执行。
放弃监视
如果监视了key,那么在 MULTI
标记事务之前,执行了 UNWATCH
,那么将释放一个事务中已被监视的所有key。