首页 > 编程知识 正文

redis mysql完美结合,redis支持事务吗

时间:2023-05-03 17:04:40 阅读:159257 作者:3584

Redis事务与传统关系数据库事务的区别传统数据库事务处理过程

在关系数据库中,打开事务并执行一系列读写操作。 最后,用户可以选择发送commit以确认以前的更改,也可以发送rollback以放弃以前的更改。

1234567891011 connection conn=.//数据库连接conn.setautocommit(false ); //打开事务try () /…添加删除更改检查sql //添加删除更改检查sql conn.commit ); //提交事务}catch(exceptione ) { conn.rollback ); //事务回滚(finally ) Conn.close ); //关闭链接} Redis事务处理进程

Redis提供的事务是打包多个命令,并一次按先进先出的顺序(FIFO )有序执行。 在执行过程中不会中断。 在事务执行过程中,其他客户端发送的命令请求不会插入到事务执行命令序列中。 事务在事务队列中的命令执行之后结束。 成功还是失败都没关系。

123456多//开始事务处理SET . //命令1入队GET . //命令1入队SADD . //命令1入队. EXEC //执行事务处理(每次1.2 Redis的事务以特殊命令MULTI开始,然后由于这种简单的事务在EXEC命令被调用之前不会执行任何实际操作,所以用户将没有办法根据根据读到的数据来做决定。这个词第一次读起来有点难懂,让我们用实例来说明这个词的意思。

通过分析MySQL(innodb )和Redis在同一需求场景下的不同实现方式,分析使用方式的差异

场景:

假设有a、b、c三个记录

在MySQL中,ABC代表同一行中记录的三个字段,初始值分别为a、b、c;

在Redis中,ABC表示三个不同的Key密钥,初始值分别为a、b、c; 我们实现这样的功能。

将a的值改变为a2,在B=b的情况下,将c改变为c2; 如果这一行不成功,1和2都不执行。 让我们来看看伪代码在MySQL中的实现

1234567891011121314151617181920 connection conn=.//获取数据库连接conn.setautocommit(false ); //事务try{ SET A=a2; 将//a的值设置为a2varb_value=select(b )读取//b的值()在频繁修改的高并发情况下需要进行此读取) if(b_value==b )布尔结果将//c转换为C2 ) if(result ) { conn.commit; //提交事务}else{ conn.rollback (; //回退事务}}catch(exceptione ) { conn.rollback ); //事务回滚(finally ) Conn.close ); //关闭链接

首先,看看Redis错误的示范,看看Redis事务的区别

1234567891011121314 valueoperationsvo=redis template.ops for value (; VO.set(a )、(a ); //初始化数据VO.set(b )、b ); VO.set(c )、(c ); redis template.setenabletransactionsupport (true; redisTemplate.multi (; //事务VO.set('a )、' a2 ); 将//a的值设置为a2 stringb _ value=string.value of (VO.get (' b ' ) ); 获取//b的值logger.info ()事务读取到b_value:' b_value ); if(b ).equals (b _ value ) ) VO.set )、) c2 ); }else logger.info ('事务结果:“JSON.tojsonstring (redis template.exec )”)

让我们看看打印结果

事务读取b_value:null事务的结果。 [true,' b'] 看出Redis事务和传统数据库的区别了吗?

第9行代码的返回值为null,因此第12行没有机会执行。

从14行打印结果中返回现有的两个返回值。 [

true,”b”],true是第8行vo.set(“A”, “a2”)的返回值,”b”是第9行(vo.get(“B”)的返回值,也就是说redis这些命令,只有才EXEC执行的时候才会真正的执行。这就是之前文章提到的“由于这种简单的事务在EXEC命令被调用之前不会执行任何实际操作,所以用户将没有办法根据根据读到的数据来做决定。”,所以在EXEC执行前我们的普通的读写操作都不会执行的,在这个过程中我们不能像传统数据库那样读DB的值来做逻辑处理。

而且还有很重要的一点,Redis是不支持已被执行命令的回滚

那么在Redis中,面对这种场景我们应该如何处理呢?怎么解决读判断,以及判断回滚呢?

那就要引入另一个关键字watch,我们先看怎么使用,再分析是怎么实现的

1234567891011121314151617 try { redisTemplate.watch("B");//监视 Key-B String b_value = String.valueOf(vo.get("B")); //获取B的值 logger.error("事务读到b_value:" + b_value); if ("b".equals(b_value)) { redisTemplate.multi(); //开始事务 vo.set("A", "a2"); //将A的值变成a2 vo.set("C", "c2"); //将C的值变成c2 logger.error("事务结果:" + JSON.toJSONString(redisTemplate.exec())); } else { redisTemplate.unwatch(); logger.error("解除watch..."); } } catch (Exception e) { redisTemplate.discard();//取消事务,放弃执行事务块内的所有命令 logger.error("取消事务,放弃执行事务块内的所有命令"); }

 

我们看一下如果在事务从“watch ~ 事务开启 ~命令入队 ~ EXEC”期间,B键的值没有被其他客户端改变的情况下的打印结果:

事务读到b_value:b事务结果:[true,true]

从打印结果,我们可以看到事务中7,8行的命令都被准确执行。

我们再Debug运行一次,这次我们把断点打在第8行,运行到第8行时我们在终端修改变B键的值:

127.0.0.1:6379> SET B b1
OK

这个时候我们让程序继续从第8行继续运行,打印结果为:

事务读到b_value:b事务结果:[]

可以看到事务中7,8行的命令都没有执行,符合我们的预期。

Redis事务分步实现

我们上面提到,Redis事务的过程分为三个阶段:

1. 事务开始2. 命令入队3. 事务执行

事务开始

Redis事务的开始是通过执行MULTI 命令来实现,它的作用是将执行该命令的客户端从非事务状态切换至事务状态, 这一切换是通过在客户端状态的 flags 属性中打开 REDIS_MULTI 标识来完成的。

命令入队

当一个客户端出于事务状态时, 如果客户端发送的命令是 EXEC(执行所有事务块内的命令) 、DISCARD(取消事务,放弃执行事务块内的所有命令。) 、 WATCH(监视任意数量的key ,提一下,在事务中执行这个命令会报错:ERR WATCH inside MULTI is not allowed) 、 MULTI(标记一个事务块的开始) 四个命令以外的其他命令,那么服务器并不立即执行这个命令,而是将这个命令放入一个事务队列里面, 然后向客户端返回 QUEUED 回复。

事务执行

当一个处于事务状态的客户端向服务器发送 EXEC 命令时, 这个 EXEC 命令将立即被服务器执行: 服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。
(这里需要说明的一点是,Redis在处理网络请求的是单线程的,所以队列中的命令在执行期间是不会被其他客户端命令插进来的。这一点对理解Redis事务很关键)

WATCH

WATCH 用于事务开启之前对任意数量的Key进行监视,如果这个被监视的key被改动(这里提一下,这个改动,不管是删除、添加、修改,或者A -> B -> A改回原值,都会被认为发生了改动),那么相应事务就被取消,否则事务正常执行。所以我们可以认为 WATCH 是一个乐观锁。
如果想让key取消被监控,可以用 UNWATCH 命令(这里又要提一下,UNWATCH 如果在事务中执行,也是会被放到队列里的)。

如上文所说,WATCH对于添加操作也是敏感的,也就说我们可以对一个不存在的Key进行WATCH。假如cli_1客户端对一个不存在的Key进行WATCH,此时cli_2客户端增加了这个键,那么cli_1客户端的事务依然不会执行,这个很有意思

后记

本应该对redis事务相关的数据结构等展开来讲,但是篇幅有限(主要是能力有限,嘘~),《Redis设计与实现》一书中已给出了很详细的介绍,所以这里就不再详述

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。