Redis初探之事务理解

前言

Redis 事务可以一次执行多个命令, 批量操作在发送 EXEC 命令前被放入队列缓存,并且带有以下两个重要的保证:
1、收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
2、在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:
开始事务。
命令入队。
执行事务。

如下图:
Redis初探之事务理解

特点

1)Redis 的事务是通过 MULTI,EXEC,DISCARD 和 WATCH 这四个命令来完成的。

2)Redis 的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。

3)Redis 将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行

4)Redis不支持回滚操作

使用

MULTI:标记事务开始
EXEC:事务执行
DISCARD:清除所有先前在一个事务中放入队列的命令
WATCH:监控事务的执行,当被监控的数据发生改变后,开启的事务执行是无法成功的,只有被监控的数据不发生变化,事务才能正常执行。
multi和exec

 > multi 
OK
 > set k1 lks
QUEUED
 > set k2 lks1
QUEUED
 > set k3 lks2
QUEUED
 > exec
1) OK
2) OK
3) OK

discard

 > set k4 lks3
QUEUED
 > set k5 lks4
QUEUED
 > discard
OK
 > exec
(error) ERR EXEC without MULTI

watch
1、开两个客户端连接
2、在第一个窗口中使用 WATCH 命令,监控 data1,并开启事务,添加设置 data2 的命令到命令队列中

> watch data1
OK
 > multi
OK
 > set data2 testdata
QUEUED

3、在第二个窗口中,改变 data1 的值

> set data1 testchange
OK

4、回到第一个窗口,执行 EXEC 命令:

exec
(nil)
 > get data2
(nil)

此时会发现返回了一个 nil,而且我们获取 data2 的值,返回的也是 nil,这就说明,当被监控的数据发生改变后,开启的事务执行是无法成功的,只有被监控的数据不发生变化,事务才能正常执行。
5、UNWATCH:清除所有先前为一个事务监控的键。

事务失败处理

事务失败主要分为Redis 语法错误Redis类型错误
Redis 语法错误

multi
OK
 > sets k7 data
(error) ERR unknown command `sets`, with args beginning with: `k7`, `data`, 
 > set k8 data8
QUEUED
 > exec
(error) EXECABORT Transaction discarded because of previous errors.
 > get k8
(nil)
127.0.0.1:6379> get k7
(nil)

在一个事务中,当命令出现错误时,后续命令正确依旧是可以添加到命令队列中去得,但是使用 EXEC 命令执行命令队列的时候,就会报错,并且队列中正确的命令也不会被执行。
Redis类型错误

multi
OK
 > set username test
QUEUED
 > lpush username lks lks2
QUEUED
 > exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
 > get username
"test"

这种错误不是命令错误,而是在执行过程中会报错,属于语法性错误,从结果来看,我们也是可以取得第一条指令设置的值,这也证明了 Redis 是不支持事务回滚的

那么为什么Redis 是不支持事务回滚的呢?
1)大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的。
2)Redis 为了性能方面就忽略了事务回滚。