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

    文章

    64

    浏览量

    7175

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

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    快断 vs 断贴片保险丝:该用哪种?看完不踩坑

    熔/延时)贴片保险丝的选择,是最容易让人困惑的环节,选错轻则导致设备频繁故障、无法正常启动,重则引发电路烧毁、元件损坏,埋下严重安全隐患。 今天就彻底拆解快断与断贴片保险丝的核心区别,讲透适用场景,帮你精准选型,
    的头像 发表于 04-10 12:35 79次阅读
    快断 vs <b class='flag-5'>慢</b>断贴片保险丝:该用哪种?看完不踩坑

    NineData 2026年3月功能上新:支持飞书外部审批,增强查询分析与数据复制能力

    NineData智能数据管理平台2026年3月新功能发布,围绕数据库 DevOps、查询分析、数据归档清理与数据复制持续升级:新增飞书 Lark 外部审批和多渠道消息通知,查询分析
    的头像 发表于 04-10 11:40 306次阅读
    NineData 2026年3月功能上新:支持飞书外部审批,增强<b class='flag-5'>慢</b><b class='flag-5'>查询</b>分析与数据复制能力

    MySQL查询调优指南

    MySQL查询是数据库性能问题的最常见原因。当一条SQL语句执行超过1秒时,就可能影响用户体验;超过10秒时,通常会收到用户投诉;而超过30秒的查询,往往意味着系统存在严重的性能问题。本文从实
    的头像 发表于 04-09 10:01 176次阅读

    MySQL数据库查询分析与优化实战

    在讨论MySQL查询之前,需要先明确一个关键前提:什么是查询? 不同业务场景下,查询的定义
    的头像 发表于 04-02 09:38 166次阅读

    SQL分析选型:DMS/DAS与NineData该如何选择

    阿里云 DMS 的SQL 趋势、DAS 的 SQL 审计能力成熟,可满足阿里云用户基础需求。NineData 侧重跨云统一工作台、研发与 DBA 协同,打通日志分析、性能诊断、规范审核、索引建议全链路,更适配企业级
    的头像 发表于 03-25 17:20 1533次阅读
    <b class='flag-5'>慢</b>SQL分析选型:DMS/DAS与NineData该如何选择

    MySQL SQL 排查这件事,NineData 社区VS DBeaver/ Navicat 技术分析

    社区版的定位不同,它是免费、本地化部署的数据管理平台,将数据库 DevOps、数据复制、数据库对比三大能力整合于一体。 在 MySQL SQL 这条链路里,它用到的是 DevOps 中的查询分析
    的头像 发表于 03-17 11:53 124次阅读
    MySQL <b class='flag-5'>慢</b> SQL 排查这件事,NineData 社区VS DBeaver/ Navicat 技术分析

    MySQL查询分析与索引调优全流程

    MySQL 性能问题在生产环境中的表现通常是渐进式的:业务量增长、数据量膨胀,某天突然发现 P99 响应时间从 50ms 涨到 2s。查询是最常见的根因,而索引设计不合理又是查询
    的头像 发表于 03-06 15:56 242次阅读

    Redis内存管理、持久化策略与查询排查分析

    Redis 在生产环境中承担着缓存、会话存储、消息队列、分布式锁等多种角色。随着数据量增长和并发压力上升,内存碎片、持久化 I/O 抖动、查询堆积这三类问题会逐渐显现,直接影响服务延迟和稳定性。Redis 8.x 在内存管理和持久化机制上做了若干改进,但核心调优思路与
    的头像 发表于 02-27 11:00 283次阅读

    微店商品列表API,轻松采集商品列表数据

    微店商品列表API是微店开放平台提供的核心接口,主要用于获取指定店铺的商品列表数据。该接口支持分页查询、条件筛选和排序功能,适用于电商管理系统、竞品分析和多平台展示等场景。 一、接口概述 1.
    的头像 发表于 12-01 14:32 561次阅读

    商品类目属性查询接口技术实现详解

    ​   一、接口核心功能 该接口用于查询电商系统中商品类目的属性信息,支持: 按类目ID查询属性集合 按属性类型过滤(关键属性$K$、销售属性$S$、普通属性$N$) 分页返回属性数据 多语言属性名
    的头像 发表于 10-11 15:43 563次阅读
    商品类目属性<b class='flag-5'>查询</b>接口技术实现详解

    数据库查询分析与SQL优化实战技巧

    今天,我将分享我在处理数千次数据库性能问题中积累的实战经验,帮助你系统掌握查询分析与SQL优化的核心技巧。无论你是刚入门的运维新手,还是有一定经验的工程师,这篇文章都将为你提供实用的解决方案。
    的头像 发表于 09-08 09:34 1230次阅读

    MySQL查询优化案例

    凌晨3点,手机疯狂震动。监控告警显示:核心业务接口响应时间超过20秒,用户投诉如潮水般涌来。这是每个运维工程师的噩梦时刻。
    的头像 发表于 08-27 14:49 815次阅读

    MySQL查询终极优化指南

    作为一名在生产环境摸爬滚打多年的运维工程师,我见过太多因为查询导致的线上故障。今天分享一套经过实战检验的MySQL查询分析与索引优化方法论,帮你
    的头像 发表于 08-13 15:55 951次阅读

    简要分析限流式保护器在某无人驾驶汽车充电站的应用

    摘 要:交流充电桩俗称“充桩”,固定安装在电动汽车外、与交流电网连接,国标采用 220V单相交流电,为电动汽车车载充电机(即固定安装在电动汽车上的充电机)提供交流电源的供电装置。国家标准
    的头像 发表于 07-08 14:28 707次阅读
    简要分析限<b class='flag-5'>流式</b>保护器在某无人驾驶汽车充电站的应用

    ASCP310系列电气防火限流式保护器安装使用说明书 V1.2

    ASCP310 系列电气防火限流式保护器是安科瑞电气专为中低压配电系统设计的智能保护设备,主要应用于电动汽车充电站、工业配电、商业建筑等场景。针对传统断路器短路响应、电弧危害大等问题,该保护器以微秒级速度快速限制短路电流,实现灭弧保护,显著降低电气火灾风险,保障用电安全
    发表于 05-17 17:32 2次下载