Skip to content

Redis事务(transactions)

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入。用来一次性、顺序性、排他性的执行一系列命令。

1. Redis事务和数据库事务区别

序号数据库事务Redis事务
1单独的隔离操作Redis的事务仅仅是保证事务里的操作会被连续独占的执行,
redis命令执行是单线程架构,在执行完事务内所有指令前是
不可能再去同时执行其他客户端的请求的
2没有隔离级别的概念因为事务提交前任何指令都不会被实际执行,也就不存在
"事务内的查询要看到事务里的更新,在事务外查询不能看到"这种问题了
3不保证原子性⚛️Redis的事务不保证原子性,也就是不保证所有指令同时成功或
同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半
进行回滚的能力
4排它性Redis会保证一个事务内的命令依次执行,而不会被其它命令插入

2. Redis事务相关命令

2.1 MULTI命令

语法: MULTI
用于标记一个事务块的开始。事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由EXEC命令原子性(atomic)地执行。

2.2 EXEC命令

语法: EXEC
用于执行事务队列内的所有命令。假如某个(或某些) key正处于WATCH命令的监视之下,且事务块中有和这个(或这些)key相关的命令,那么EXEC命令只在这个(或这些)key没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。

2.3 DISCARD命令

语法: DISCARD
取消事务,放弃执行事务队列内的所有命令,恢复连接为非事务模式。如果正在使用WATCH命令监视某个(或某些) key,那么会取消所有监视,等同于执行命令UNWATCH

2.4 WATCH命令

语法: WATCH key [key ...]
用于标记要监视的key,以便有条件地执行事务。WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行成功。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值),WATCH命令是一种乐观锁🔏的实现。

2.5 UNWATCH命令

语法: UNWATCH
用于取消WATCH命令对所有key的监视。如果执行过EXECDISCARD,无需再执行UNWATCH。因为EXEC命令执行默认就取消所有对key的监视;而DISCARD命令在取消事务的同时也会取消所有对key的监视,因此这两个命令执行之后,就没有必要执行UNWATCH了。

3. 事务相关命令组合使用

Redis使用MULTI命令标记事务开始,它总是返回OK。MULTI执行之后,客户端可以发送多条命令,Redis会把这些命令保存在队列当中,而不是立刻执行这些命令。所有的命令会在调用EXEC命令之后执行。
如果不调用EXEC,调用DISCARD会清空事务队列并退出事务。
当Redis连接执行MULTI命令后,之后所有的命令返回字符串QUEUED

3.1 正常顺利执行

multi命令和exec命令组合使用

sh
192.168.101.105:6379> multi
OK
192.168.101.105:6379(TX)> set k1 v11
QUEUED
192.168.101.105:6379(TX)> set k2 v22
QUEUED
192.168.101.105:6379(TX)> lpush mylist a b c d e f
QUEUED
192.168.101.105:6379(TX)> exec
1) OK
2) OK
3) (integer) 6
192.168.101.105:6379> lrange mylist 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"

3.2 取消执行

multi命令和discard命令组合使用

sh
192.168.101.105:6379> multi
OK
192.168.101.105:6379(TX)> hset mymap name jack age 123
QUEUED
192.168.101.105:6379(TX)> zadd zset1 100 jack 80 yuanyuan 82 xiaomi
QUEUED
192.168.101.105:6379(TX)> discard
OK
192.168.101.105:6379> hget mymap name
(nil)

3.3 执行前报错

在调用EXEC之前出错,命令加入队列失败。例如命令的参数个数不符,或者内存补足。

sh
192.168.101.105:6379> multi
OK
192.168.101.105:6379(TX)> zadd myset 30 jack 40 xiaoli 50 anna
QUEUED
192.168.101.105:6379(TX)> zcount myset
(error) ERR wrong number of arguments for 'zcount' command
192.168.101.105:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
192.168.101.105:6379> zcount myset -inf +inf
(integer) 0

3.4 执行中报错

命令在执行EXEC之后失败,例如对错误值类型的key执行操作(像在字符串值上执行列表操作)。

sh
192.168.101.105:6379> multi
OK
192.168.101.105:6379(TX)> setbit user_sign_log:001 0 0
QUEUED
192.168.101.105:6379(TX)> setbit user_sign_log:001 3 1
QUEUED
## bitmap类型数据只能存储0和1
192.168.101.105:6379(TX)> setbit user_sign_log:001 2 123
QUEUED
192.168.101.105:6379(TX)> getbit user_sign_log:001 3
QUEUED
192.168.101.105:6379(TX)> exec
1) (integer) 0
2) (integer) 0
3) (error) ERR bit is not an integer or out of range
4) (integer) 1

3.5 watch和unwatch命令使用

WATCH用于为 Redis事务提供检查和设置(CAS)行为。WATCHMULTIEXEC组合使用,Redis在修改的时候会检测数据是否被更改,如果更改了,则执行失败,返回nil。如果key数据已经被修改,执行unwatch命令提前结束对key的监控。

sh
## 命令行窗口1
192.168.101.105:6379> watch k1
OK
192.168.101.105:6379> get k1
"v11"
192.168.101.105:6379> multi
OK
192.168.101.105:6379(TX)> set k1 v111
QUEUED

## 命令行窗口2
[root@hadoop105 bin]# ./redis-cli -a jack 
## 抢先执行同一数据操作
127.0.0.1:6379> set k1 vvvv
OK
## 命令行窗口1
192.168.101.105:6379(TX)> exec
(nil)
192.168.101.105:6379> get k1
"vvvv"