前言

当指定查询数据过大时,我们一般使用分页查询的方式,一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据,如果一下子将数据全部加载出来到内存中,很可能会发生OOM。这时我们可以使用流式查询解决问题。

非流式查询

为了更好的复现问题,将jvm参数,最大堆设置成212M。使用mysql数据库,表大小为730MB。

非流式查询表里所有数据代码

List infoPOs = infoMapper.selectList(new EntityWrapper<>());

通过查看idea控制台,很快出现了内存溢出。

通过jconsole工具,查看内存使用情况

在14.26,发现内存直接被释放了。

流式查询

流式查询表里所有数据代码

@Select("select * from t_iot")

@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)

@ResultType(InfoPO.class)

void selectAutoList(ResultHandler handler);

infoMapper.selectAutoList(resultContext -> {

resultContext.getResultObject();

});

通过查看idea控制台,程序运行正常

在通过jconsole工具,查看内存使用情况

发现内存消耗处于平稳状态。

流式查询原理

查看源码可知,我们使用流式查询时,必须要满足以下3个条件

/**

* We only stream result sets when they are forward-only, read-only, and the

* fetch size has been set to Integer.MIN_VALUE

*

* @return true if this result set should be streamed row at-a-time, rather

* than read all at once.

*/

protected boolean createStreamingResultSet() {

return ((this.query.getResultType() == Type.FORWARD_ONLY) && (this.resultSetConcurrency == java.sql.ResultSet.CONCUR_READ_ONLY)

&& (this.query.getResultFetchSize() == Integer.MIN_VALUE));

}

resultSetConcurrency=ResultSet.CONCUR_READ_ONLY 设置只读结果集

resultSetType = ResultSetType.FORWARD_ONLY 设置结果集的游标只能向下滚动

fetchSize = Integer.MIN_VALUE 设置fetch size为int的最小值,这里和oracle/db2有区别.

Oracle/db2是从服务器一次取出fetch size 条记录放在客户端,客户端处理完成一个批次后再向服务器取下一个批次,直到所有数据处理完成。

mysql在执行ResultSet.next()方法时,会通过数据库连接一条一条的返回。MySQL按照自己的节奏不断的把buffer写回网络中。flush buffer的过程是阻塞式的,也就是说如果网络中发生了拥塞,send buffer被填满,会导致buffer一直flush不出去,那MySQL的处理线程会阻塞,从而避免数据把客户端内存撑爆。

设置三个参数之后,断点进入到了流式返回结果集ResultsetRowsStreaming。

ResultSet数据返回的结果,对象有3种实现方式

ResultsetRowsStatic 静态结果集,默认的查询方式,普通查询

ResultsetRowsCursor 游标结果集,服务器端基于游标查询

ResultsetRowsStreaming 动态结果集,流式查询

查看ResultsetRowsStatic类注释

/**

* Represents an in-memory result set

*/

public class ResultsetRowsStatic extends AbstractResultsetRows implements ResultsetRows {

表示放在内存中的结果集。

查看ResultsetRowsStreaming类注释

/**

* Provides streaming of Resultset rows. Each next row is consumed from the

* input stream only on {@link #next()} call. Consumed rows are not cached thus

* we only stream result sets when they are forward-only, read-only, and the

* fetch size has been set to Integer.MIN_VALUE (rows are read one by one).

*

* @param

* ProtocolEntity type

*/

public class ResultsetRowsStreaming extends AbstractResultsetRows implements ResultsetRows {

提供了Resultset行的流。获取下一行都是从仅在{@link #next()}调用时输入流。因此不会缓存已使用的行。我们只在结果集只有前进、只读和时才流结果集获取大小已设置为整数。MIN_VALUE(逐个读取行)。

总结

之前使用过db2处理流式查询,设置的fetch size为100,没有问题。这次使用mysql刚开始时也设置的100,发现内存溢出了,后来在网上看到mysql流式获取数据的坑,debug进去果然没走到ResultsetRowsStreaming类,设置fetch size 参数为Integer.MIN_VALUE后,才进了ResultsetRowsStreaming类。

mysql 流式查询_Mybatis流式查询避免OOM相关推荐

  1. mybatis plus 多表查询_Mybatis 多表查询之一对多

    本次案例主要以最为简单的用户和账户的模型来分析Mybatis多表关系.用户为User 表,账户为Account 表.一个用户(User)可以有多个账户(Account).具体关系如下: 3.1 一对一 ...

  2. mybatis 分页查询_MyBatis之分页查询:MyBatis PageHelper

    MyBatis,作为目前流行的ORM框架,大大方便了日常开发.而对于分页查询,虽然可以通过SQL的limit语句实现,但是比较繁琐.而MyBatis PageHelper的出现,则解决了这一痛点.这里 ...

  3. mysql mapper配置模糊查询_Mybatis各种模糊查询

    模糊查询: 工作中用到,写三种用法吧,第四种为大小写匹配查询 1. sql中字符串拼接 SELECT * FROM tableName WHERE name LIKE CONCAT(CONCAT('% ...

  4. mysql流式查询mybatis_流式查询:MyBatis千万级数据查询解决方案,避免OOM

    来源:segmentfault.com/a/1190000022478915 哈喽,各位新来的小伙伴们,大家好!由于公众号做了改版,为了保证公众号的资源能准时推送到你手里,大家记得将咱们的公众号加星标 ...

  5. 大数据量查询:流式查询与游标查询

    最近在做一个计算相关的功能,大体就是有很多条SQL,每条SQL都涉及复杂地运算,最后要将所有计算结果进行合并分析.经初步测试,每个SQL起码会查出几十万条记录,我们现在有毛毛多的这种SQL. 最大的问 ...

  6. mybatis中mysql流式读取_MyBatis读取大量数据(流式读取)

    ## 一.背景 导出大量数据时,虚拟机频繁GC,内存耗尽,CPU爆满,可采用Mybatis数据流式读取进行优化. ## 二.JDBC三种读取方式: 1. 一次全部(默认):一次获取全部. 2. 流式: ...

  7. ef关联多实体查询_Mybatis基本知识十二:关联关系查询之延迟加载:侵入式延迟加载...

    上一篇文章:<Mybatis基本知识十一:关联关系查询之延迟加载策略:直接加载> 若文中有纰漏,请多多指正!!! 1.前言 延续上一章节,本章节主要讲解和演示在关联关系查询中侵入式延迟加载 ...

  8. 流体式布局与响应式布局_将固定像素设计转换为流体比例布局

    流体式布局与响应式布局 Responsive web design has been a prime necessity for every enterprise ever since Google ...

  9. CSS3与页面布局学习笔记(四)——页面布局大全(负边距、双飞翼、多栏、弹性、流式、瀑布流、响应式布局)

    一.负边距与浮动布局 1.1.负边距 所谓的负边距就是margin取负值的情况,如margin:-100px,margin:-100%.当一个元素与另一个元素margin取负值时将拉近距离.常见的功能 ...

最新文章

  1. Case Study: 利用PHP获取关系型数据库中多张数据表的数据
  2. 华为云 和 阿里云 跨服务器搭建Hadoop集群
  3. jvm内存结构_浅谈JVM内存结构
  4. 设置SSH免密码自动登录(使用别名)
  5. php+获取jq表单数据类型,jquery怎么获取表单标签值
  6. CMOS模拟集成电路设计课程
  7. Android JTT808协议通讯
  8. [Python]ImportError: This platform lacks a functioning sem_open implementation, therefore, the requi
  9. ZZULIOJ1076-1080Python解法
  10. Linux安装phpMywind
  11. ngro_k服务器搭建(本地电脑与微信交互)
  12. Python spiders基础学习笔记
  13. 巧为tomcat插件配置log4j日志,解决未报错启动不成功
  14. .NET获取硬盘序列号的几个方法
  15. 驻极体ECM)和硅麦(MEMS)麦克参数介绍
  16. python底层是用什么语言实现的_我为何说Python是全栈式开发语言?
  17. 大数据分析案例-基于多元线性回归算法构建用户信用评分模型
  18. Swan Song 第十一周Scrum Meeting
  19. XTDrone仿真平台与Prometheus仿真平台
  20. linux 安装tomcat教程(配图详解)

热门文章

  1. android7.1 msm8953通过寄存器拉高gpio电平
  2. 中国大学moocpython_中国大学慕课mooc2020用Python玩转数据期末考试公众号答案
  3. 多元线性回归算法预测房价
  4. 纯css DIV弹出动画
  5. cad在计算机领域的应用论文,CAD技术在生产中的应用(毕业论文).doc
  6. 安卓APP全局黑白化实现方案
  7. 人工智能数据标注案例大全【1】人脸关键点标注
  8. .net DataExcel 控件开发使用说明
  9. 微信小程序商品界面实现,顶部固定,解决顶部内容重叠问题,动态加载顶部标签栏
  10. 基于matlab的sift变换的图像配准和拼接算法仿真