试验环境:
- centos7.6x64位,CentOS-7-x86_64-Minimal-1810.iso
百度网盘下载地址:https://pan.baidu.com/s/1ckjQS_DGuI-7GGvmvhLNKQ 提取码: 6gfc linux的安装参照:centos7.6最小化安装
- redis-5.0.5.tar.gz
官网下载地址:http://download.redis.io/releases/redis-5.0.5.tar.gz 百度网盘下载地址:https://pan.baidu.com/s/1ipnB043h5Tvk7cYGKxSr8g 提取码: bdkh
参照:
- 概念参考:https://www.runoob.com/redis/redis-transactions.html
- 操作命令参考:http://doc.redisfans.com/
- 优秀博文:Redis之Redis事务
- 优秀博文:Redis的事务和watch
一、概念说明
redis中的事务与数据库的事务是不同的概念:数据库的事务具有ACID(是原子性、一致性、隔离性和持久性),而redis中的事务没有这些。 一句话概括:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
总结下来redis事务有以下特点:
- redis事务不可嵌套
- redis事务开始于mutil,结束于exec或discard
- 在开始事务之前可以使用watch命令监视一个或多个键的值,如果监控到改变,那么随后的事务如果是在值改变之后执行的(exec)就会被舍弃
- redis事务一旦开始执行,其他的客户端命令是不能插入执行的
- redis事务执行时,如果其中命令有语法错误会导致整个事务被丢弃(不执行);如果其中命令执行报错,那么这条命令不会对事务队列中其他的命令造成影响
二、事务命令的执行细节
2.1 细节说明
redis事务涉及到的命令:
- watch/unwatch
- mutil
- exec/discard
下图展示一个事务执行的顺序:
对上图的解释:
- 客户端A执行watch a和watch b后将a和b加入到 “监控区”
- 客户端A执行unwatch后将a和b从 “监控区” 中移除
- 客户端A执行watch c后将c加入到 “监控区”(此时c的值为c1)
- 客户端A执行multi标记一个事务开始
- 客户端A执行set name jack和set age 28后将这两条命令加入到 “事务队列”
- 客户端A执行exec后将 “监控区” 和 “事务队列” 发送到redis服务端
- redis服务端接收到客户端A的 “事务队列” 和 “监控区” 后先进行判断,如果c的值未发生改变就执行 “事务队列” 后将结果返回,否则就直接返回空.
注意: 上面图中有几个细节没有画出来:
- 假如在命令3和4之间(即:watch c和multi之间)改变了c的值,那么这个事务是否被执行呢?
事务不会被执行,因为一旦开启检测,之后的更改都会导致事务被丢弃,而且无论是谁更改的都会被丢弃(自己改的也不行)。
- exec执行后监控区里面还有监控的值吗?
exec执行后无论成功或失败,监控区里的东西都会被清空。同样,如果你执行了discard,那么监控区的东西也会被清空。
- 事务队列的命令如果执行出错怎么办?会回滚吗?
首先,redis中的事务就是将一批命令打捆一起执行(其他的客户端命令不能插入),所以不存在回不回滚的说法。 其次,如果事务中的命令是因为执行出错的话(比如:incr name,而name的值是一个字符串),那么它将不影响它前后的命令执行;如果事务中的命令是语法错误(比如:mgetset name),那么整个事务队列里的命令都不会被执行,事实上,在向事务队列中加入语法错误的命令时,客户端就已经提示出错了。
2.2 实验证明上述细节
好吧,上面是比较正常的操作,实验不出来问题,下面将用几个实验证明细节问题。
三、实验事务执行细节(使用一个redis-cli客户端即可)
3.1 证明开启watch后,一旦对watch的值进行修改,将导致其后的事务失效
3.2 可以在multi后修改watch的值而不影响事务的执行
3.3 证明multi/exec/discard不能嵌套,并且exec和discard要和multi一一对应
3.4 语法错误和执行出错的情况
语法错误情况:
执行出错情况:
3.5 unwatch命令前的监控将不会影响到后续事务的执行