myabtis流式查询

news2024/11/26 14:33:19

1、流式查询简介

流式处理在大数据方面应用比较广泛。随着数据的爆发式增长,流式处理的方式也被应用到日常的工具中,如JDK的对于集合处理的Stream流、Redis5.0新增的数据结构Stream专门来处理消息等。

流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。

今天要分享的是Mybaits的流式查询。Mybatis流式查询通过使用游标一次处理一条数据的方式,减少了内存的占用,从而提高了大数据量查询的效率。

2、Mybaits流式查询

Mybaits3.4.0 版本增加了流式查询也就是游标Cursor。更新日志传动门,Issues · mybatis/mybatis-3 · GitHub

2.1 游标简介

游标的使用和List一样,只不过返回的结果不同。

游标继承CloseableIterable接口,所以游标是可关闭、可遍历的。包含三个方法:

  • isOpen 游标的开关是否打开

  • isConsumed 通过游标是否将拉取的数据消费完,也就是是否将数据全部取完。

  • getCurrentIndex 获取当前数据的位置,位置是从0开始的。

2.2 游标的使用

定义简单的查询方法,这里使用注解@Select的方式代替Xml,方便测试。

@Select("select * from logan_log.logan_login")
Cursor<LoganLogin> testCursorQuery();

编写测试类。因为游标是可关闭的,所以使用完之后要想流一样关闭掉。这里采用try-resource 的方式简化流的关闭。

@Test
void testCursorSql() {
	try (Cursor<LoganLogin> cursor = loganLoginMapper.testCursorQuery()) {
		cursor.forEach((ll) -> {
			System.out.println("ll:" + JSON.toJSONString(ll));
			System.out.println("ll cursor:" + cursor.getCurrentIndex());
		});
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}

处理结果,报错了。。。

原因分析:

  • A Cursor is already closed. 还没有处理数据,查询完数据之后游标被关闭了。

  • 由于Mybatis帮我们做了自动事务的提交。查询完毕之后就会提交事务关闭连接,游标自然也被关闭了,就会出现这样的问题。游标需要占用数据库的连接,然后逐条的将数据返回的。

解决方案:

  • 将整个方法放在一个事务里面,处理完数据之后在提交事务。比较暴力的解决方案就是使用声明式事务@Transactional。大事务的处理可能会影响业务的并发。

  • 采用小颗粒度的编程式事务TransactionTemplate,只针对流式查询的结果包装到一个事务里面即可。

  • 也可以采用手动提交事务,使用SqlSessionFactory手动建立连接和关闭。

编程式事务解决问题可能更方便一些,所以采用编程式事务的方法解决。

@Test
void testCursorSql2() {
	transactionTemplate.execute(new TransactionCallbackWithoutResult() {
		@Override
		protected void doInTransactionWithoutResult(TransactionStatus status) {
			System.out.println("TransactionStatus1:" + status.hasSavepoint());
			try (Cursor<LoganLogin> cursor = loganLoginMapper.testCursorQuery()) {
				cursor.forEach((ll) -> {
					System.out.println("ll:" + JSON.toJSONString(ll));
					System.out.println("ll cursor:" + cursor.getCurrentIndex());
				});
				System.out.println("TransactionStatus2:" + status.hasSavepoint());
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	});
}

结果正常打印

2.3 游标查询的升级

游标的使用总会便随着事务,对于开发者来说成了黄金搭档。能不能将其封装成一个方法来方便开发者调用呢,还真有。就是使用ResultHandler参数。

有人就提出了对应的issues,同时也在mybatis-3.4.6得到了支持。

2.3.1 ResultHandler参数说明

ResultHandler 作为参数参数传递,返回值为Void。xml的配置需要指定ResultType

查询到的结果,也是封装在ResultHandler 里面的ResultContext中。

  • T getResultObject() 返回的数据结果

  • int getResultCount() 返回当前结果的记录数据。

  • boolean isStopped() 是否停止拉取数据

  • void stop() 中断数据拉取

2.3.2 ResultHandler的使用

ResultHandler 的使用,官方文档中已经给出使用案例。我们来测试一下。

先定义一下方法。同样采用注解的方式替代xml

@ResultType(LoganLogin.class)
@Select("select * from logan_log.logan_login")
void testStreamQuery(ResultHandler<LoganLogin> handler);

其中ResultType 必须要指定,否则就会报错。

测试案例

@Test
void testStreamSql() {
	loganLoginMapper.testStreamQuery(resultContext -> {
		System.out.println("handleResult:" + JSON.toJSONString(resultContext.getResultObject()));
		System.out.println("ResultCount:" + resultContext.getResultCount());
		System.out.println("isStop:" + resultContext.isStopped());
		System.out.println("---------------------------------------");
	});
}

测试结果

2.4 fetchSize 的讨论

很多技术博客中都强调,fetchSize 可以控制每次拉取的数量。

但是笔者配置,测试之后发现并没有什么效果。在使用流式查询时,官方文档中也没有说明必须要配置。

元芳,你怎么看???

3、流式查询在Mybatis-Plus中的使用

mybatis中已经支持了流式查询,那么好用的MP怎么会不支持。MP在3.5.4中也得到了支持。

具体的方法如下:

/**
 * 根据 entity 条件,查询全部记录
 *
 * @param queryWrapper  实体对象封装操作类(可以为 null)
 * @param resultHandler 结果处理器 {@link ResultHandler}
 * @since 3.5.4
 */
void selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);/**
 * 根据 entity 条件,查询全部记录(并翻页)
 * @param page          分页查询条件
 * @param queryWrapper  实体对象封装操作类(可以为 null)
 * @param resultHandler 结果处理器 {@link ResultHandler}
 * @since 3.5.4
 */
void selectList(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);
/**
 * 根据 Wrapper 条件,查询全部记录
 *
 * @param queryWrapper  实体对象封装操作类
 * @param resultHandler 结果处理器 {@link ResultHandler}
 * @since 3.5.4
 */
void selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
/**
 * 根据 Wrapper 条件,查询全部记录(并翻页)
 *
 * @param page          分页查询条件
 * @param queryWrapper  实体对象封装操作类
 * @param resultHandler 结果处理器 {@link ResultHandler}
 * @since 3.5.4
 */
void selectMaps(IPage<? extends Map<String, Object>> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
/**
 * 根据 Wrapper 条件,查询全部记录
 * <p>注意: 只返回第一个字段的值</p>
 *
 * @param queryWrapper  实体对象封装操作类(可以为 null)
 * @param resultHandler 结果处理器 {@link ResultHandler}
 * @since 3.5.4
 */
<E> void selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<E> resultHandler);

就拿最典型的selectList来测试。

没有分页的查询。其中Wrapper主要是查询的Sql 的条件拼接,也可以是空。ResultHandler就是我们的流式返回了。

@Test
void testStreamPlus() {
	loganLoginMapper.selectList(Wrappers.emptyWrapper(), resultContext->{
		System.out.println("handleResult:" + JSON.toJSONString(resultContext.getResultObject()));
		System.out.println("ResultCount:" + resultContext.getResultCount());
		System.out.println("isStop:" + resultContext.isStopped());
		System.out.println("---------------------------------------");
	});
}

测试结果

有分页的查询和无分页方法是重载关系,增加了分页参数Page。其中Page只是限定了拉取数据的总条数,但是并不会自动封装到Page对象中。主要使用了, resultContextstop的方法。

@Test
void testStreamPage() {
	Page<LoganLogin> page = new Page<>(1, 2);
	loganLoginMapper.selectList(page, Wrappers.emptyWrapper(), resultContext->{
		System.out.println("当前处理第" + resultContext.getResultCount() + "条记录.");
		System.out.println("handleResult:" + JSON.toJSONString(resultContext.getResultObject()));
		System.out.println("isStop:" + resultContext.isStopped());
		System.out.println("---------------------------------------");
	});
	System.out.println(JSON.toJSONString(page.getRecords()));
}

测试结果

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

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

相关文章

景联文科技:高质量数据采集清洗标注服务,助力大语言模型红蓝对抗更加精准高效

红蓝对抗是一种测试和评估大语言模型的方法。通过模拟真实世界测试AI模型的潜在漏洞、偏见和弱点&#xff0c;确保大型语言模型的可靠性和性能。 在红蓝对抗过程中&#xff0c;由主题专家组成的专业团队负责模拟攻击和提供反馈&#xff0c;他们试图诱导AI模型产生不当行为&…

电子商务平台对接电商供应链,不得不说的开放平台电商API接口

B2B电商开放平台的设计需要从以下几面去思考&#xff1a; 开放平台API接口的设计&#xff0c;主要是从功能需求的角度&#xff0c;设计满足业务需求的接口及对应的字段&#xff1b; 平台与商家之间信息的对接&#xff0c;对接的方法有哪些&#xff1f;对接过程中需要可能会遇到…

PaDiM 无监督异常检测和定位-论文和源码阅读

目录 1. 论文 1.1 检测效果 1.2 框架 1.2.1 特征提取embedding extraction 1.2.2 正样本学习Learning of the normality 1.2.3 计算异常图 inference: computation of the anomaly map 2. 源码 2.1 dataset 2.2 model 2.3 提取特征 1. 论文 https://arxiv.org/abs/…

Redis 6.0 新功能

1-支持 ACL 1.1-ACL 简介 官网&#xff1a;https://redis.io/topics/acl Redis ACL 是访问控制列表(Access Control List)的缩写&#xff0c;该功能允许根据可以执行的命令和可以访问的键来限制某些连接。 Redis 5 版本之前&#xff0c;Redis 安全规则只有密码控制&#xf…

Python元编程详细教程

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 简单定义“元编程是一种编写计算机程序的技术&#xff0c;这些程序可以将自己看做数据&#xff0c; 因此你可以在运行时对它进行内审、生成和/或修改”&#xff…

SpringCloud篇---第三篇

系列文章目录 文章目录 系列文章目录一、负载平衡的意义什么?二、什么是Hystrix?它如何实现容错?三、什么是Hystrix断路器?我们需要它吗?一、负载平衡的意义什么? 在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多 种计算资源的…

超高真空变温台的真空压力和气氛精密控制解决方案

摘要&#xff1a;针对目前国内外显微镜探针冷热台普遍缺乏真空压力和气氛环境精密控制装置这一问题&#xff0c;本文提出了解决方案。解决方案采用了电动针阀快速调节进气和排气流量的动态平衡法实现0.1~1000Torr范围的真空压力精密控制&#xff0c;采用了气体质量流量计实现多…

配置OpenCV

Open CV中包含很多图像处理的算法&#xff0c;因此学会正确使用Open CV也是人脸识别研究的一项重要工作。在 VS2017中应用Open CV&#xff0c;需要进行手动配置&#xff0c;下面给出在VS2017中配置Open CV的详细步骤。 1.下载并安装OpenCV3.4.1与VS2017的软件。 2.配置Open CV环…

纠结蓝桥杯参加嵌入式还是单片机组?

纠结蓝桥杯参加嵌入式还是单片机组? 单片机包含于嵌入式&#xff0c;嵌入式不只是单片机。. 你只有浅浅的的单片机基础&#xff0c;只能报单片机了。最近很多小伙伴找我&#xff0c;说想要一些单片机资料&#xff0c;然后我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵…

Selenium安装WebDriver Chrome驱动(含 116/117/118/119/120/)

1、确认浏览器的版本 在浏览器的地址栏&#xff0c;输入chrome://version/&#xff0c;回车后即可查看到对应版本 2、找到对应的chromedriver版本 2.1 114及之前的版本可以通过点击下载chromedriver,根据版本号&#xff08;只看大版本&#xff09;下载对应文件 2.2 116版本…

1. eulerAngles函数

对线性代数库Eigen3中eulerAngles函数的理解_qingtian11112的博客-CSDN博客作用&#xff1a; 将旋转矩阵转换为欧拉角 Vector3f ea mat.eulerAngles(2, 0, 2); // 等价于 mat AngleAxisf(ea[0], Vector3f::UnitZ())* AngleAxisf(ea[1], Vector3f::UnitX())* AngleAxisf(ea[…

《Pytorch新手入门》第二节-动手搭建神经网络

《Pytorch新手入门》第二节-动手搭建神经网络 一、神经网络介绍二、使用torch.nn搭建神经网络2.1 定义网络2.2 torch.autograd.Variable2.3 损失函数与反向传播2.4 优化器torch.optim 三、实战-实现图像分类(CIFAR-10数据集)3.1 CIFAR-10数据集加载与预处理3.2 定义网络结构3.3…

99/年服务器测评,续费也99一年,真香,值得入手

每个帐号都有开通名额&#xff0c;开通99元一年&#xff0c;配置2核2G 40G 3M(不限流量)&#xff0c;续费也是99一年 开通之后就可以直接续费&#xff0c;免除后顾之忧&#xff08;一年一年的去续费&#xff0c;直接选择5年价格不太对&#xff09; 地址&#xff1a;https://mur…

成为java高手的八个条件

成为java高手的八个条件 1、扎实的基础 数据结构、离散数学、编译原理&#xff0c;这些是所有计算机科学的基础&#xff0c;如果不掌握它们&#xff0c;很难写出高水平的程序。程序人人都会写&#xff0c;但当你发现写到一定程度很难再提高的时候&#xff0c;就应该想想是不…

投资者如何保障个人利益?行业律师与欧科云链专家给出建议

香港作为全球加速拥抱Web3变革的引领之地&#xff0c;规定自今年6月起在香港经营虚拟资产服务业务需申领牌照。蜂拥而至的Web3创业公司&#xff0c;伺机而动的加密货币交易所&#xff0c;以及跃跃欲试的行业从业者&#xff0c;都让这座金融之都热闹非凡。但近期伴随JPEX诈骗案等…

HarmonyOS UI 开发

引言 HarmonyOS 提供了强大的 UI 开发工具和组件&#xff0c;使开发者能够创建吸引人的用户界面。本章将详细介绍在 HarmonyOS 中应用 JS、CSS、HTML&#xff0c;HarmonyOS 的 UI 组件以及如何自定义 UI 组件。 目录 JS、CSS、HTML 在 HarmonyOS 中的应用HarmonyOS 的 UI 组…

使用 Sealos 将 ChatGLM3 接入 FastGPT,打造完全私有化 AI 客服

FastGPT 是一款专为客服问答场景而定制的开箱即用的 AI 知识库问答系统。该系统具备可视化工作流功能&#xff0c;允许用户灵活地设计复杂的问答流程&#xff0c;几乎能满足各种客服需求。 在国内市场环境下&#xff0c;离线部署对于企业客户尤为重要。由于数据安全和隐私保护…

springboot--多环境配置快速切换开发、测试、生产环境

多环境配置快速切换开发、测试、生产环境 前言1、使用1.1指定环境Profile({"dev","test"})Spring Profiles 提供一个隔离配置的方式&#xff0c;使其仅在特定环境生效 任何Component,Configuration或ConfigurationProperties 可以使用Profile标记&#xff…

11.2树的高度,表达式树,非递归遍历,层序遍历,奇偶树

课上 前序&#xff0c;根左右 中序&#xff0c;左根右 若前序中序相同&#xff0c;则树都没有左节点 求树的高度 表达式树 中缀表达式树 主要考虑括号问题 这个就是考虑递归底层&#xff0c;要结束时的情形&#xff1b;以及根节点的情形&#xff1b; 由于表达式树是满树&…