性能文章>数据库中使用流式查询避免数据量过大导致OOM的优化>

数据库中使用流式查询避免数据量过大导致OOM的优化转载

2月前
137000

导语

通常情况下,Mybatis将查询结果返回成一个集合 ,如果集合过大,可能出现内存溢出情况。本篇是一篇mybatis数据库优化实战,内容相对比较简单,适合初级开发者阅读!

 

正文

今天mybatis查询数据库中大量的数据,程序抛出:

java.lang.OutOfMemoryError: Java heap space


看下日志,是因为一次查询数据量过大导致JVM内存溢出了,虽然可以配置JVM大小,但是指标不治本,还是需要优化代码。网上查看大家都是流式查询,这里记录下解决的过程。

01、Mapper.xml配置

select语句需要增加fetchSize属性,底层是调用jdbc的setFetchSize方法,查询时从结果集里面每次取设置的行数,循环去取,直到取完。默认size是0,也就是默认会一次性把结果集的数据全部取出来,当结果集数据量很大时就容易造成内存溢出。

 <select id="listTaskResultIpInfo" fetchSize="1000" resultType="String">
        select info from task_result_info where project_id = #{projectId} and task_id = #{taskId}
    </select>

 

 

注意:此时需要在mysql连接URL中增加useCursorFetch=true。

jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useCursorFetch=true

02、自定义ResultHandler

 

package com.iie.test.handler.result;

import com.iie.test.entity.po.custom.CustTaskResultInfo;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by bo on 2019/8/23.
 * MyBatis中使用流式查询避免数据量过大导致OOM
 */
public class ResultInfoHandler implements ResultHandler<CustTaskResultInfo> {
    // 存储每批数据的临时容器
    private List<CustTaskResultInfo> resultInfoList = new ArrayList<>();

    public List<CustTaskResultInfo> getResultInfoList() {
        return resultInfoList;
    }

    @Override
    public void handleResult(ResultContext<? extends CustTaskResultInfo> resultContext) {
        CustTaskResultInfo custTaskResultInfo = resultContext.getResultObject();
        resultInfoList.add(CustTaskResultInfo);
    }

}


03、spring中配置sqlSessionTemplate

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
        <!-- mapper扫描 -->
        <property name="mapperLocations" value="classpath:mybatis/mapper/*/*.xml"/>
    </bean>
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>


04、service中使用

 

   @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
  
public List<CustTaskResultInfo> listTaskResultInfo(Long projectId, Long taskId) {
        Map<String, Object> param = new HashMap<>();
        param.put("projectId", projectId);
        param.put("taskId", taskId);
        ResultInfoHandler handler = new ResultInfoHandler();
        sqlSessionTemplate.select("com.iie.cyberpecker.dao.custom.CustTaskResultInfoMapper.listTaskResultInfo", param, handler);
        return handler.getResultInfoList();
    } 


推荐下我的 IDEA 视频,里面很多骚操作:https://www.bilibili.com/video/BV187411n7xF

05、疑问

上面这种方案必须要定义一个sqlSessionTemplate,我想着能不能直接在mapper.xml中配置,网上说的是这样实现:

1E30E751-B8AB-4971-BEDB-A482224AE2E2.png


但是我这样实现一直没有成功,查询数据为空,有遇到同样问题解决的可以留言给我。

分类:标签:
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

构建企业级业务高可用的延时消息中台
业务场景剖析公司业务系统(比如:电商系统)中有大量涉及定时任务的业务场景,例如:实现买卖双方在线沟通的IM系统,为了确保接收方能够收到消息,服务端一般都会有重试策略,即服务端在消息发出的一段时间内,如
5G时代,如何彻底搞定海量数据库的设计与实践
5G时代,业务数据越来越丰富,业务使用MySQL数据库作为后台存储,存储引擎使用InnoDB,会带来哪些挑战?如何针对公司业务特点及MySQL数据库特性,制定若干数据库使用规范供一线RD在设计业务时参
Redis client链接池配置不当引起的频繁full gc
现象笔者负责的一个RPC服务就是简单的从Redis Cluster中读取数据,然后返回给上游。理论上该服务的对象大部分都应该是朝生夕死的,但是笔者查看gc log 的时候发现 age =2 的对象还真
记一次线上请求偶尔变慢的排查
前言最近解决了个比较棘手的问题,由于排查过程挺有意思,于是就以此为素材写出了本篇文章。 Bug现场这是一个偶发的性能问题。在每天几百万比交易请求中,平均耗时大约为300ms,但总有那么100多笔会超过
MySQL之KEY分区引发的血案
需求背景业务表tb_image部分数据如下所示,其中id唯一,image_no不唯一。image_no表示每个文件的编号,每个文件在业务系统中会生成若干个文件,每个文件的唯一ID就是字段id:业务表t
从一次数据库问题排查实战
前言上周五,一同事在开发时遇到了一个问题,叫我帮忙看下.在描述这个同事遇到问题之前,我先简单做一些知识的铺垫,否则不好描述.这里面涉及到的知识点有Spring的事务传播机制、数据库的隔离级别等.本篇重
Java:基于AOP的动态数据源切换(附源码)
1 动态数据源的必要性我们知道,物理服务机的CPU、内存、存储空间、连接数等资源都是有限的,某个时段大量连接同时执行操作,会导致数据库在处理上遇到性能瓶颈。而在复杂的互联网业务场景下,系统流量日益膨胀。为了解决这个问题,行业先驱门充分发扬了分而治之的思想,对大库表进行分割,然后实施更好的控制和
数据库中使用流式查询避免数据量过大导致OOM的优化
导语通常情况下,Mybatis将查询结果返回成一个集合 ,如果集合过大,可能出现内存溢出情况。本篇是一篇mybatis数据库优化实战,内容相对比较简单,适合初级开发者阅读! 正文今天mybatis查询数据库中大量的数据,程序抛出:java.lang.OutOfMemoryErro