Redis 事务介绍
- Redis 的事务是通过 MULTI,EXEC,DISCARD 和 WATCH 这四个命令来完成的。
- Redis 的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。
- Redis 将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行
- Redis不支持回滚操作
相关命令
在介绍 Redis 事务相关命令前,我们先上一张图,这张图很好的描述了 Redis 事务的执行过程,在图里体现了部分命令,WATCH 命令会在后面单独介绍,需要注意的一点是这张图里面的 queue 队列,理解它的作用,然后再结合相关命令的介绍,就能够很快搞明白 Redis 事务。
1)MULTI:用于标记事务块的开始。Redis 会将后续的命令逐个放入队列中,然后使用 EXEC 命令原子化地执行这个命令序列。
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379> set k1 alan # 设置 k1
QUEUED # k1 加入队列
127.0.0.1:6379> set k2 tom # 设置 k2
QUEUED # k2 加入队列
2)EXEC:在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
127.0.0.1:6379> exec
1) OK
2) OK
使用 EXEC 命令原子化地执行这个命令序列,刚刚我们设置了 k1 和 k2 两条命令,执行EXEC 命令后,给我们反馈了两个 OK,说明上述两条命令全部执行成功。
3)DISCARD:清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k3 lucy
QUEUED
127.0.0.1:6379> set k4 jack
QUEUED
127.0.0.1:6379> discard
OK
4)WATCH:当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的状态。注意:使用该命令可以实现 Redis 的乐观锁。
(1)对于 WATCH 命令的演示就稍微麻烦一些,这里我们在 Xshell 中开启两个 ssh 渠道,并且都连接到了单机的 Redis 服务(两个 ssh 渠道连接的是同一个 Redis 服务)
(2)在第一个窗口中使用 WATCH 命令,监控 data1,并开启事务,添加设置 data2 的命令到命令队列中
(3)然后在第二个窗口中,改变 data1 的值
(4)回到第一个窗口,执行 EXEC 命令,此时会发现返回了一个 nil,而且我们获取 data2 的值,返回的也是 nil,这就说明,当被监控的数据发生改变后,开启的事务执行是无法成功的,只有被监控的数据不发生变化,事务才能正常执行。
5)UNWATCH:清除所有先前为一个事务监控的键。
3、事务失败处理
1)Redis 语法错误(可以理解为编译期错误)
在一个事务中,当命令出现错误时,后续命令正确依旧是可以添加到命令队列中去得,但是使用 EXEC 命令执行命令队列的时候,就会报错,并且队列中正确的命令也不会被执行。
2)Redis 类型错误(可以理解为运行期错误)这种错误不是命令错误,而是因为对命令理解不透彻出现的使用错误,在执行过程中会报错,因为 username1 不是 list 类型,它只是一个 string 类型。有一点需要注意,从结果可以看出,第一条命令是执行成功了的,所有我们使用"get username1"命令,返回了"alan"结果,这也证明了 Redis 是不支持事务回滚的。
3)为什么 Redis 不支持事务回滚?
(1)大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的。
(2)Redis 为了性能方面就忽略了事务回滚。
Linux、C/C++技术交流群:整理了一些C/C++ Linux服务器架构师学习资料(加群获取)(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
想要搞明白 Redis 事务,一定要先理解文中那张图解,了解 queue 命令队列,以及各个命令是如何操作命令队列的,还要特别注意 WATCH 命令,了解它的运行原理以及使用场景,最为重要的是一定要知道 Redis 事务失败后是如何处理的,分为了两种情况,还要能说明为什么 Redis 是不支持事务回滚的,了解了这些东西就 OK 了。