Redis 事务机制

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

一、常用命令


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

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

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

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

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

二、WATCH 监控


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

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

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

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

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

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

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

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

三、小结


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

 
posted @ 2020-11-20 13:19  Java程序员进阶  阅读(280)  评论(0编辑  收藏  举报