【Redis学习系列】Redis事务

/ Redis / 没有评论 / 1200浏览

Redis 事务

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

127.0.0.1:6379> multi      #事务以multi为开始,开启一个事务
OK
127.0.0.1:6379> set k1 v1	 #以实际的redis命令为中间阶段
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec			#以exec执行为结束阶段;
1) OK
2) OK
3) OK
4) "v2"
5) "v3"

单个 Redis 命令的执行是原子性的!

但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

运行时异常:中途错误命令不会影响后续命令的执行。

127.0.0.1:6379> flushdb
OK
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> incr k1 	#中间阶段有一步报错
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec			# 执行后发现;报错不会妨碍k3值的写入
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
4) OK
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

编译性异常:中途出现错误,后续操作不被执行

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> getset k2
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

discard取消事务

discard 命令用于取消事务,放弃执行事务块内的所有命令。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> get key1
QUEUED
127.0.0.1:6379> set k2
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI

watch

watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

正常情况:

127.0.0.1:6379> set money 100     #设置钱包100元
OK
127.0.0.1:6379> set out 0				  #设置支出0元
OK
127.0.0.1:6379> watch money       #监视钱包
OK
127.0.0.1:6379> multi							#开启事务
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec							#执行事务
1) (integer) 80
2) (integer) 20

异常情况:

客户端1:

127.0.0.1:6379> mget money out      #1 查看当前钱包余额 & 支出月
1) "80"
2) "20"
127.0.0.1:6379> watch money         #2 监视当前钱包余额
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10       #先不执行,去客户端2执行命令
QUEUED
127.0.0.1:6379> exec								# 4 执行事务
(nil)																#返回nil 执行失败!

客户端2:

root@AY140210092026Z:~# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> incrby money 100   #3 改变钱包余额充值100元
(integer) 180

unwatch

unwatch 命令用于取消 WATCH 命令对所有 key 的监视。

127.0.0.1:6379> unwatch
OK