试验环境:

  • 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

下图展示一个事务执行的顺序:

redis如何保证事务性 redis如何保证事务唯一性_redis如何保证事务性

对上图的解释:

  • 客户端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如何保证事务性 redis如何保证事务唯一性_redis如何保证事务性_02

好吧,上面是比较正常的操作,实验不出来问题,下面将用几个实验证明细节问题。

三、实验事务执行细节(使用一个redis-cli客户端即可)

3.1 证明开启watch后,一旦对watch的值进行修改,将导致其后的事务失效

redis如何保证事务性 redis如何保证事务唯一性_redis_03

3.2 可以在multi后修改watch的值而不影响事务的执行

redis如何保证事务性 redis如何保证事务唯一性_事务_04

3.3 证明multi/exec/discard不能嵌套,并且exec和discard要和multi一一对应

redis如何保证事务性 redis如何保证事务唯一性_语法错误_05

3.4 语法错误和执行出错的情况

语法错误情况:

redis如何保证事务性 redis如何保证事务唯一性_语法错误_06

执行出错情况:

redis如何保证事务性 redis如何保证事务唯一性_语法错误_07

3.5 unwatch命令前的监控将不会影响到后续事务的执行

redis如何保证事务性 redis如何保证事务唯一性_事务_08