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

# 一、常用命令

【1】MULTI: 开启一个事务
【2】EXEC : 执行事务中的命令。可以看到 MULTI 开始到 EXEC 之间,所有的命令都会被加入到一个命令队列中。当执行 EXEC 命令后,将 QUEUED 中所有的命令执行
【3】DISCARD: 放弃事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set redis "redis"
QUEUED
127.0.0.1:6379> get redis
QUEUED
127.0.0.1:6379> sadd tag "java" "c" "c#"
QUEUED
127.0.0.1:6379> smembers tag
QUEUED
127.0.0.1:6379> exec
1) OK
2) "redis"
3) (integer) 3
4) 1) "c#"
   2) "java"
   3) "c"

#放弃执行案例
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set mysql "mysql"
QUEUED
127.0.0.1:6379> get mysql
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get mysql
(nil)
127.0.0.1:6379> 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

常见的两种状况: ①、全体连坐(当语法有错时,一条都不成功)②、冤头债主(当时编译时出错,部分可以成功)

WARNING

Redis 的事务没有提供类似于关系型数据库的回滚(rollback),所以开发人员必须在事务执行失败后进行后续的处理。

每个 Redis 客户端都有自己的事务状态,保存在 multiState 属性中,进一步,每一个事务状态包含一个事务队列以及已入队命令的计数器,事务队列是一个数组,数组中的每个元素保存了已入队命令的相关信息,包含指向命令实现函数的指针、命令的参数,以及参数的数量。

Cluster

# 二、WATCH 监控

在 Nosql 数据库中,CAS 是一种保证原子性的操作。Redis 也提供了这样的一个机制,就是利用 Watch命令来实现的。Watch 指令,类似乐观锁(悲观锁:锁整张表。乐观锁:锁一行数据),事务提交时,如果 Key 的值已被别的客户端改变,比如某个 list已被别的客户端 push/pop 过了,整个事务队列都不会被执行,通过 WATCH 命令在事务执行之前监控了多个 Keys,倘若在WATCH 之后有任何 Key 的值发生了变化,EXEC 命令执行的事务都将被放弃,同时返回 Nullmulti-bulk 应答以通知调用者事务执行失败。

【1】客户端1: 对 key = redis 的值进行监控,并开启事务后对 key = redis 的数据进行修改。如下:

127.0.0.1:6379> watch redis 
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set redis "redis"
QUEUED
1
2
3
4
5
6

【2】客户端2: 直接对 key = redis 的值进行修改。如下:

127.0.0.1:6379> set redis "re"
OK
1
2

【3】客户端1: 执行 EXEC 提交事务,会发现执行失败。当获取 redis 值时,发现是客户2修改的值。

127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get redis
"re"
1
2
3
4

UNWATCH: 取消监控,与 WATCH 命令相反。当指向提交事务EXEC 或取消事务DISCARD 时,会自动执行 UNWATCH 取消客户端对某 key 的监控

# 三、小结

3 阶段:
【1】开启:以MULTI开始一个事务
【2】入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
【3】执行:由EXEC命令触发事务

3 特性:
【1】单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
【2】没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在 ”事务内的查询要看到事务里的更新,在事务外查询不能看到” 这个让人万分头痛的问题。
【3】不保证原子性:redis 同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

(adsbygoogle = window.adsbygoogle || []).push({});