0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MyBatis流式查询轻松帮你解决分页慢的问题

5jek_harmonyos 来源:思否开发者社区 作者:捏造的信仰 2021-08-04 15:52 次阅读

作者丨捏造的信仰

segmentfault.com/a/1190000022478915

Part1基本概念

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

如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。

流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。

Part2MyBatis 流式查询接口

MyBatis 提供了一个叫 org.apache.ibatis.cursor.Cursor 的接口类用于流式查询,这个接口继承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:

Cursor 是可关闭的。实际上当关闭 Cursor 时,也一并将数据库连接关闭了;

Cursor 是可遍历的。

除此之外,Cursor 还提供了三个方法:

isOpen():用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据;

isConsumed():用于判断查询结果是否全部取完;

getCurrentIndex():返回已经获取了多少条数据。

因为 Cursor 实现了迭代器接口,因此在实际使用当中,从 Cursor 取数据非常简单:

try(Cursor cursor = mapper.querySomeData()) {

cursor.forEach(rowObject -》 {

// 。。。

});

}

使用 try-resource 方式可以令 Cursor 自动关闭。

Part3但构建 Cursor 的过程不简单

我们举个实际例子。下面是一个 Mapper 类:

@Mapper

public interface FooMapper {

@Select(“select * from foo limit #{limit}”)

Cursor《Foo》 scan(@Param(“limit”) int limit);

}

方法 scan() 是一个非常简单的查询。我们在定义这个方时,指定返回值为 Cursor 类型,MyBatis 就明白这个查询方法是一个流式查询。

然后我们再写一个 SpringMVC Controller 方法来调用 Mapper(无关的代码已经省略):

@GetMapping(“foo/scan/0/{limit}”)

public void scanFoo0(@PathVariable(“limit”) int limit) throws Exception {

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) { // 1

cursor.forEach(foo -》 {}); // 2

}

}

假设 fooMapper 是 @Autowired 进来的。注释 1 处是获取 Cursor 对象并保证它能最后关闭;2 处则是从 cursor 中取数据。

上面的代码看上去没什么问题,但是执行 scanFoo0(int) 时会报错:

java.lang.IllegalStateException: A Cursor is already closed.

这是因为我们前面说了在取数据的过程中需要保持数据库连接,而 Mapper 方法通常在执行完后连接就关闭了,因此 Cusor 也一并关闭了。

所以,解决这个问题的思路不复杂,保持数据库连接打开即可。我们至少有三种方案可选。

方案一:SqlSessionFactory

我们可以用 SqlSessionFactory 来手工打开数据库连接,将 Controller 方法修改如下:

@GetMapping(“foo/scan/1/{limit}”)

public void scanFoo1(@PathVariable(“limit”) int limit) throws Exception {

try (

SqlSession sqlSession = sqlSessionFactory.openSession(); // 1

Cursor《Foo》 cursor =

sqlSession.getMapper(FooMapper.class).scan(limit) // 2

) {

cursor.forEach(foo -》 { });

}

}

上面的代码中,1 处我们开启了一个 SqlSession (实际上也代表了一个数据库连接),并保证它最后能关闭;2 处我们使用 SqlSession 来获得 Mapper 对象。这样才能保证得到的 Cursor 对象是打开状态的。

方案二:TransactionTemplate

在 Spring 中,我们可以用 TransactionTemplate 来执行一个数据库事务,这个过程中数据库连接同样是打开的。代码如下:

@GetMapping(“foo/scan/2/{limit}”)

public void scanFoo2(@PathVariable(“limit”) int limit) throws Exception {

TransactionTemplate transactionTemplate =

new TransactionTemplate(transactionManager); // 1

transactionTemplate.execute(status -》 { // 2

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) {

cursor.forEach(foo -》 { });

} catch (IOException e) {

e.printStackTrace();

}

return null;

});

}

上面的代码中,1 处我们创建了一个 TransactionTemplate 对象(此处 transactionManager 是怎么来的不用多解释,本文假设读者对 Spring 数据库事务的使用比较熟悉了),2 处执行数据库事务,而数据库事务的内容则是调用 Mapper 对象的流式查询。注意这里的 Mapper 对象无需通过 SqlSession 创建。

方案三:@Transactional 注解

这个本质上和方案二一样,代码如下:

@GetMapping(“foo/scan/3/{limit}”)

@Transactional

public void scanFoo3(@PathVariable(“limit”) int limit) throws Exception {

try (Cursor《Foo》 cursor = fooMapper.scan(limit)) {

cursor.forEach(foo -》 { });

}

}

它仅仅是在原来方法上面加了个 @Transactional 注解。这个方案看上去最简洁,但请注意 Spring 框架当中注解使用的坑:只在外部调用时生效。在当前类中调用这个方法,依旧会报错。

以上是三种实现 MyBatis 流式查询的方法。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mybatis
    +关注

    关注

    0

    文章

    60

    浏览量

    6712

原文标题:还在担心分页慢吗? MyBatis 流式查询解决你的烦恼

文章出处:【微信号:harmonyos_developer,微信公众号:harmonyos_developer】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Mybatis 拦截器实现单数据源内多数据库切换

    作者:京东保险 王奕龙 物流的分拣业务在某些分拣场地只有一个数据源,因为数据量比较大,将所有数据存在一张表内查询速度,也为了做不同设备数据的分库管理,便在这个数据源内创建了多个不同库名但表完全相同
    的头像 发表于 12-12 10:23 704次阅读

    什么是虚拟内存分页 Windows系统虚拟内存优化方法

    虚拟内存分页概述 在Windows操作系统中,虚拟内存是通过分页机制实现的。分页允许系统将内存中的数据移动到硬盘上,以便为当前运行的程序腾出空间。这个过程对于保持系统的流畅运行至关重要,尤其是在物理
    的头像 发表于 12-04 09:16 308次阅读

    Simplelink™ CC3220-OV788音频/视频流式传输参考

    电子发烧友网站提供《Simplelink™ CC3220-OV788音频/视频流式传输参考.pdf》资料免费下载
    发表于 09-02 11:13 0次下载
    Simplelink™ CC3220-OV788音频/视频<b class='flag-5'>流式</b>传输参考

    滑动变阻器限流式分压式接法区别

    滑动变阻器是一种常见的电子元件,用于调节电路中的电阻值。在实际应用中,滑动变阻器的接法主要有两种:限流式和分压式。这两种接法在电路设计和应用中有着不同的优缺点和适用范围。 一、限流式接法 工作原理
    的头像 发表于 08-05 14:37 3056次阅读

    流式滑动变阻器的选型原则

    流式滑动变阻器,又称为限流电阻器或限流电位器,是一种用于限制电路中电流大小的电子元件。在电子电路设计中,选择合适的限流式滑动变阻器对于确保电路的稳定运行和提高电路性能至关重要。 一、限流式滑动
    的头像 发表于 08-05 14:31 871次阅读

    使用mybatis切片实现数据权限控制

    一、使用方式 数据权限控制需要对查询出的数据进行筛选,对业务入侵最少的方式就是利用mybatis或者数据库连接池的切片对已有业务的sql进行修改。切片逻辑完成后,仅需要在业务中加入少量标记代码
    的头像 发表于 07-09 17:26 363次阅读
    使用<b class='flag-5'>mybatis</b>切片实现数据权限控制

    流式继电器工作特性有哪些

    流式继电器是一种利用整流原理实现继电器触点切换的电子元件,广泛应用于电力系统、工业自动化、通信设备等领域。 整流式继电器的工作原理 整流式继电器的工作原理基于整流原理。当输入电压达到一定值
    的头像 发表于 06-28 10:26 750次阅读

    流式继电器输入的是什么电源

    流式继电器是一种常见的电气元件,广泛应用于电力系统、工业自动化、通信设备等领域。它的核心功能是将输入的交流电源转换为直流电源,以驱动继电器的线圈,实现对电路的控制。本文将详细介绍整流式继电器
    的头像 发表于 06-28 10:21 789次阅读

    流式继电器与无极继电器的区别

    在电气工程和自动化领域,继电器是一种非常重要的控制元件。继电器的主要作用是接收输入信号,然后根据输入信号的状态来控制输出电路的通断。根据其工作原理和结构特点,继电器可以分为很多种类,其中整流式继电器
    的头像 发表于 06-28 10:17 958次阅读

    流式继电器结构上有哪些特点

    流式继电器是一种利用整流原理来实现继电器动作的电气设备,广泛应用于电力系统、工业自动化、通信设备等领域。本文将详细介绍整流式继电器的结构特点,包括其工作原理、主要组成部分、性能指标、应用场景等方面
    的头像 发表于 06-28 10:15 1003次阅读

    流式继电器属于什么继电器

    流式继电器是一种特殊类型的继电器,它主要用于将交流电转换为直流电。这种继电器在许多应用中都非常重要,例如在电力系统中,它可以用于控制和保护设备。在本文中,我们将详细介绍整流式继电器的工作原理、类型
    的头像 发表于 06-28 10:07 723次阅读

    分库分表后复杂查询的应对之道:基于DTS实时性ES宽表构建技术实践

    分表,通过分库分表应对存系统读写性能瓶颈和存储瓶颈;分库分表帮我们解决问题的同时,也带来了复杂性;比如多条件的分页查询,多条件的联表查询变得复杂起来,通过调研我们发现针对这些分页,联表
    的头像 发表于 06-25 18:30 861次阅读
    分库分表后复杂<b class='flag-5'>查询</b>的应对之道:基于DTS实时性ES宽表构建技术实践

    影响电动汽车交流充时间的因素有哪些?

    影响电动汽车交流充时间的因素有哪些? 电动汽车的充时间受到多个因素的影响。下面将详细介绍这些因素,并解释它们是如何影响充时间的。 首先,电动汽车的充时间受到电动汽车电池的容量的
    的头像 发表于 04-08 16:13 1105次阅读

    让你的年终总结更有格调!讯飞星火AI商务键盘帮你轻松撰写

    亲爱的朋友们,年底了,是不是已经开始忙碌起来准备年终总结了呢?别担心,我们有科大讯飞AI智能键盘D1来帮你轻松撰写! 首先,让我来为大家介绍一下这款神奇的键盘。它拥有讯飞星火认知大模型,这可是我们
    的头像 发表于 01-05 15:46 536次阅读
    让你的年终总结更有格调!讯飞星火AI商务键盘<b class='flag-5'>帮你</b><b class='flag-5'>轻松</b>撰写

    SQL改写消除相关子查询实践

    GaussDB (DWS) 根据子查询在 SQL 语句中的位置把子查询分成了子查询、子链接两种形式。
    的头像 发表于 12-27 09:51 512次阅读