12-Redis - 事务
案例1:事务的简单操作
127.0.0.1:6379> keys * (empty list or set) 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> EXEC 1) OK 2) OK 3) "v2" 4) OK 127.0.0.1:6379>
放弃执行命令
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> set k3 33 QUEUED 127.0.0.1:6379> DISCARD OK 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379>
(1)在一个事务中,只要有一条命令是错误的,那么整个事务就执行失败,由于事务的原子性,数据自动恢复到事务执行之前的状态
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> getset k3 (error) ERR wrong number of arguments for 'getset' command 127.0.0.1:6379> set k4 44 QUEUED 127.0.0.1:6379> set k5 55 QUEUED 127.0.0.1:6379> EXEC (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k5 (nil) 127.0.0.1:6379>
(2)下面的事务中,有一条命令是错误的,但是这个事务中的其他命令照样执行,指示不执行错误的那条命令
127.0.0.1:6379> keys * 1) "k2" 2) "k3" 3) "k1" 127.0.0.1:6379> get k1 "11" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3" 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> INCR k1 QUEUED 127.0.0.1:6379> INCR k2 QUEUED 127.0.0.1:6379> set k4 v4 QUEUED 127.0.0.1:6379> set k5 v5 QUEUED 127.0.0.1:6379> EXEC 1) (integer) 12 2) (error) ERR value is not an integer or out of range 3) OK 4) OK 127.0.0.1:6379> get k1 "12" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3" 127.0.0.1:6379> get k4 "v4" 127.0.0.1:6379> get k5 "v5" 127.0.0.1:6379>
总结以上的(1)和(2),(1)中是命令在事务之中就报错了(相当于Java中编译时就报错了),(2)中是命令在事务之中没报错,在执行的时候报错(相当于Java中的执行时报错),但是(1)中的事务中的所有命令都不执行,而(2)中的事务中的命令只是错误的没执行,正确的命令却照样执行。所以Redis对事务的支持的结论是:
Redis部分执行事务
1. 当在入队时发生错误时就支持事务的原子性(支持事务,所有命令要么一起成功,要么一起失败)
2. 当在入队时不发生错误,但是在执行的时候发生错误,这时候Redis就不支持事务(不支持事务的原子性,正确的命令允许执行,错误的命令阻止执行)
事务案例1:模拟余额和欠债
(1)开始余额100元,欠债0元,花了20元,余额变80,欠债20
(2)第二次监听balance。(1)中的事务完成后,又继续监听balance(左边),而监听完了之后,在右边(模拟另外一个人),有人给余额充值200元
左边的这个人又花了20,欠债增加20,结果是nil(执行不成功)
接着左边那哥们儿查了下余额balance,发现余额变成了280(因为余额100,第一次花了20,余额变成了80,但是在第二次花销之前,有人给他充值了200,所以余额280)
这时候欠债还是20
在事务的中间发现数据修改之后,使用watch命令监听到事务被中途更改之后立即unwatch,然后重新watch之后,再继续接下来的修改操作就不会报错
注意:unwatch命令是针对所有key进行监视