Redis的基础事务

Redis 存在事务,尽管它没有数据库那么强大,但是它还是很有用的,尤其是在那些需要高并发的网站当中。

使用 Redis 读/写数据要比数据库快得多,如果使用 Redis 事务在某种场合下去替代数据库事务,则可以在保证数据一致性的同时,大幅度提高数据读/写的响应速度。

互联网和传统企业管理系统不一样,互联网系统面向的是公众,很多用户同时访问服务器的可能性很大,尤其在一些商品抢购、抢红包等场合,对性能和数据的一致性有着很高的要求,而存储系统的读/写响应速度对于这类场景的性能的提高是十分重要的。

在 Redis 中,也存在多个客户端同时向 Redis 系统发送命令的并发可能性,因此同一个数据,可能在不同的时刻被不同的线程所操纵,这样就出现了并发下的数据一致的问题。为了保证异性数据的安全性,Redis 为提供了事务方案。而 Redis 的事务是使用 MULTI-EXEC 的命令组合,使用它可以提供两个重要的保证:

	事务是一个被隔离的操作,事务中的方法都会被 Redis 进行序列化并按顺序执行,事务在执行的过程中不会被其他客户端发生的命令所打断。事务是一个原子性的操作,它要么全部执行,要么就什么都不执行。

在一个 Redis 的连接中,请注意要求是一个连接,所以更多的时候在使用 Spring 中会使用 SessionCallback 接口进行处理,在 Redis 中使用事务会经过 3 个过程:

	开启事务。命令进入队列。执行事务。

Redis事务命令
在这里插入图片描述

在 Redis 中开启事务是 multi 命令,而执行事务是 exec 命令。multi 到 exec 命令之间的 Redis 命令将采取进入队列的形式,直至 exec 命令的出现,才会一次性发送队列里的命令去执行,而在执行这些命令的时候其他客户端就不能再插入任何命令了,这就是 Redis 的事务机制。

Redis 命令执行事务的过程。
在这里插入图片描述

从图中可以看到,先使用 multi 启动了 Redis 的事务,因此进入了 set 和 get 命令,我们可以发现它并未马上执行,而是返回了一个“QUEUED”的结果。

这说明 Redis 将其放入队列中,并不会马上执行,当命令执行到 exec 的时候它就会把队列中的命令发送给 Redis 服务器,这样存储在队列中的命令就会被执行了,所以才会有“OK”和“value1”的输出返回。

如果回滚事务,则可以使用 discard 命令,它就会进入在事务队列中的命令,这样事务中的方法就不会被执行了,使用 discard 命令取消事务如图所示。
在这里插入图片描述

当我们使用了 discard 命令后,再使用 exec 命令时就会报错,因为 discard 命令已经取消了事务中的命令,而到了 exec 命令时,队列里面已经没有命令可以执行了,所以就出现了报错的情况。

在 Spring 中要使用同一个连接操作 Redis 命令的场景,这个时候我们借助的是 Spring 提供的 SessionCallback 接口,采用 Spring 去实现上述命令,代码如下所示。

ApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
SessionCallback callBack = (SessionCallback) (RedisOperations ops)-> {ops.multi();ops.boundValueOps("key1").set("value1");//注意由于命令只是进入队列,而没有被执行,所以此处采用get命令,而value却返回为nullString value = (String) ops.boundValueOps("key1").get();System.out.println ("事务执行过程中,命令入队列,而没有被执行,所以value为空: value="+value);//此时list会保存之前进入队列的所有命令的结果List list = ops.exec(); //执行事务//事务结束后,获取value1value = (String) redisTemplate.opsForValue().get("key1");return value;
};
//执行Redis的命令
String value = (String)redisTemplate.execute(callBack);
System.out.println(value);

这里采用了 Lambda 表达式(注意,Java 8 以后才引入 Lambda 表达式)来为 SessionCallBack 接口实现了业务逻辑。从代码看,使用了 SessionCallBack 接口,从而保证所有的命令都是通过同一个 Redis 的连接进行操作的。

在使用 multi 命令后,要特别注意的是,使用 get 等返回值的方法一律返回为空,因为在 Redis 中它只是把命令缓存到队列中,而没有去执行。使用 exec 后就会执行事务,执行完了事务后,执行 get 命令就能正常返回结果了。

最后使用 redisTemplate.execute(callBack); 就能执行我们在 SessionCallBack 接口定义的 Lambda 表达式的业务逻辑,并将获得其返回值。执行代码后可以看到这样的结果,如图所示:
在这里插入图片描述

这里打印出来的 value=null,是因为在事务中,所有的方法都只会被缓存到 Redis 事务队列中,而没有立即执行,所以返回为 null。如果我们希望得到 Redis 执行事务各个命令的结果,可以用这行代码:

List list = ops.exec(); //执行事务

这段代码将返回之前在事务队列中所有命令的执行结果,并保存在一个 List 中,我们只要在 SessionCallback 接口的 execute 方法中将 list 返回,就可以在程序中获得各个命令执行的结果了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/564087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis事务回滚深入

对于 Redis 而言,不单单需要注意其事务处理的过程,其回滚的能力也和数据库不太一样,这也是需要特别注意的一个问题——Redis 事务遇到的命令格式正确而数据类型不符合,如图所示。 从图中可知,我们将 key1 设置为字符串…

计算机辅助设计的发展及应用,计算机辅助设计的发展与应用

计算机维普资讯 http://doc.xuehai.net第 1卷第 34 2、期19 98年 9月株洲工学院学报V 11 o34 o 2N .、 .J OURNAL OF HUZ Z HOU NS TUTE OF TEC I TI HNOL OGY S p 1 9 e .98⑦计算机辅助设计的发展与应用7摘要廖建勇(洲工学院株株洲 420) 1 0 87讨论计算机辅助设计( AD) c技术…

Java 画圆

Java控制台画圆 画空心圆 完整代码: //空心圆 import java.util.Scanner; class circle2 { public static void main(String[] args) { new circle2().print();} //画圆函数void print() {System.out.println("输入半径:"); Sca…

智能控制和计算机控制的区别,解析智能控制技术是什么及与传统控制的区别

描述智能控制是什么智能控制(intelligent controls)在无人干预的情况下能自主地驱动智能机器实现控制目标的自动控制技术。对许多复杂的系统,难以建立有效的数学模型和用常规的控制理论去进行定量计算和分析,而必须采用定量方法与定性方法相结合的控制方…

C++ 画直线

使用C画直线 完整代码 #include "graphics.h" int main() {int driver,mode,i;float x0,y0,y1,x1;float j12,k;driverVGA;modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(GREEN);x0263;y0263;y1275;x1275;for(i0;i<18;i){setcolor(5);lin…

计算机系统性错误,《深入理解计算机系统-异常》

现代操作系统通过使控制流发生突变来对某些意外情况(磁盘读写数据准备就绪、硬件定时器产生信号等)做出反应。一般而言&#xff0c;我们把这些突变命名为异常控制流(Exceptional Contral Flow ECF)。异常控制流发生在计算机系统的各个层次。比如&#xff0c;在硬件层&#xff0…

C 画矩形

使用C画矩形 使用C语言的相关知识在控制台输出一个矩形。 完整代码 #include "graphics.h" int main() {int x0,y0,y1,x1,driver,mode,i;driverVGA;modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(YELLOW);x0263;y0263;y1275;x1275;for(i0;…

C++ 画圆

C画圆 使用C技术在控制台输出一个圆形。 完整代码 # define PAI 3.1415926 # define B 0.809 # include "graphics.h" #include "math.h" int main() {int i,j,k,x0,y0,x,y,driver,mode;float a;driverCGA;modeCGAC0;initgraph(&driver,&mode,&…

C 画图

使用C语言画图 使用C语言相关知识画图。 完整代码 #include "graphics.h" #define LEFT 0 #define TOP 0 #define RIGHT 639 #define BOTTOM 479 #define LINES 400 #define MAXCOLOR 15 int main() {int driver,mode,error;int x1,y1;int x2,y2;int dx1,dy1,dx2,…

C 杨辉三角形

使用C语言实现杨辉三角形 C语言使用循坏输出10行的杨辉三角形。 完整代码&#xff1a; #include <stdio.h>int main() {int i,j;int a[10][10];printf("\n");for(i0;i<10;i) {a[i][0]1;a[i][i]1;}for(i2;i<10;i)for(j1;j<i;j)a[i][j]a[i-1][j-1]a[…

计算机项目开发流程,产品开发项目建议流程图怎样画

产品开发项目建议流程图怎样画2019-01-14 10:30:270点赞3收藏0评论每一个新产品即将问世的时候会对其进行一系列的测试&#xff0c;测试的结果以及需要更改的地方我们会用表格将其整理起来&#xff0c;流程图就是一个比较实用的图表&#xff0c;可以清晰的看到整件事情的操作流…

C 画点

C语言画点 使用C语言画点。 完整代码 #include "stdio.h" #include "graphics.h" int main() {int i,j,driverVGA,modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(YELLOW);for(i50;i<230;i20)for(j50;j<230;j)putpixel(i,j…

C 画椭圆

C语言画圆 使用C语言画椭圆。 完整代码 #include "stdio.h" #include "graphics.h" #include "conio.h" int main() {int x360,y160,driverVGA,modeVGAHI;int num20,i;int top,bottom;initgraph(&driver,&mode,"");topy-30…

C++ 画图

使用C画图 C实现画图&#xff0c;采用ellipse and rectangle实现。 完整代码 #include "stdio.h" #include "graphics.h" #include "conio.h" main() {int driverVGA,modeVGAHI;int i,num15,top50;int left20,right50;initgraph(&driver,…

计算机办公价格,公职人员,你的办公电脑最少要用6年,而价格不能超过这个数?...

小王&#xff0c;是个公职人员&#xff0c;每天的工作&#xff0c;都离不开电脑。可是&#xff0c;他的电脑最近似乎不太给力&#xff0c;而且动不动就死机。有一次&#xff0c;领导在开会前&#xff0c;着急要个发言材料&#xff0c;就把这活安排给了小王。还有一个小时&#…

C 画美丽的图案

C语言画图案 使用C语言技术画一个美丽的图案在控制台输出。 完整代码 #include "graphics.h" #include "math.h" #include "dos.h" #include "conio.h" #include "stdlib.h" #include "stdio.h" #include &quo…

flume 写入文件服务器,Flume环境配置以及基本操作

flume的作用是从接受外界的日志信息&#xff0c;然后输出到本地的一个框架。agent是Flume很重要的组成&#xff0c;包括有source&#xff0c;channel&#xff0c;sink。source是从外部接受日志。channel跟内存相似&#xff0c;读满了之后再写到sink中。sink是将数据写到本地&am…

C 字符串个数

C语言求字符串个数。 使用C语言获取输入的字符串并计算字符串的个数在控制台输出显示字符串个数。 完整代码 #include <stdio.h> #include <stdlib.h> int main() {int len;char str[20];printf("请输入字符串:\n");scanf("%s",str);lenlen…

Redis发布订阅模式

使用银行卡消费的时候&#xff0c;银行往往会通过微信、短信或邮件通知用户这笔交易的信息&#xff0c;这便是一种发布订阅模式&#xff0c;这里的发布是交易信息的发布&#xff0c;订阅则是各个渠道。这在实际工作中十分常用&#xff0c;Redis 支持这样的一个模式。 发布订阅…

Redis的超时命令和垃圾回收策略

正如 Java 虚拟机&#xff0c;它提供了自动 GC&#xff08;垃圾回收&#xff09;的功能&#xff0c;来保证 Java 程序使用过且不再使用的 Java 对象及时的从内存中释放掉&#xff0c;从而保证内存空间可用。 当程序编写不当或考虑欠缺的时候&#xff08;比如读入大文件&#x…