Redis 事务的本质就是一次性、顺序性、排他性的执行一个队列中的一系列命令
Redis命令如下:
- MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。
- EXEC:执行事务中的所有操作命令。
- DISCARD:取消事务,放弃执行事务块中的所有命令。
- WATCH:监视一个或多个key,如果事务在执行前,key(或多个key)被其他命令修改,则事务被中断,不执行事务中的任何命令。
- UNWATCH:取消WATCH对所有key的监视
基本使用
情况一:标准事务的执行
1 | 127.0.0.1:6379> multi |
情况二:事务取消
1 | 127.0.0.1:6379> multi |
情况三:事务异常(语法异常)
开启事务后,修改k1值为111,修改k2的值为222,但是语法错误,导致提交的时候都保留原值
1 | 127.0.0.1:6379> multi |
情况四:事务异常(运行时异常)
开启事务后,修改k1值为1111,修改k2的值为2222,但是类型错误,都能提交,执行时只有一个成功一个失败
1 | 127.0.0.1:6379> multi |
也就是说,当事务提交后,并不能保证所有的请求都能成功,可能出现一部分成功,一部分失败
WATCH
WATCH
命令可以为 Redis 事务提供 check-and-set(CAS)行为
被 WATCH
的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC
返回nil-reply
来表示事务已经失败
假设需要原子性地为某个值进行增 1 操作(假设 INCR 不存在),开两个窗口:
-
另一个在执行过程中(
exec
提交事务前执行修改操作)修改key1
set k5 3
-
一个执行 Watch 并执行事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14127.0.0.1:6379> watch k5
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k5 2
QUEUED
127.0.0.1:6379(TX)> set k6 1
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379> get k5
"3"
127.0.0.1:6379> get k6
(nil)
可以看出得出的结果是 3,另外需要注意的是 k6 的值也设置失败,也就是事务所有请求都失败了(而且测试发现全部失败与命令在事务的第几条没有关系 )