《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/bobozai86/article/details/100033076 「波波仔86」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

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

java.lang.OutOfMemoryError: Java heap space

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

1、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

2、自定义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;

/**
* 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);
}

}

3、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>

4、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();
}

5、疑问

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

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

文章目录
  1. 1. 1、Mapper.xml配置
  2. 2. 2、自定义ResultHandler
  3. 3. 3、spring中配置sqlSessionTemplate
  4. 4. 4、service中使用
  5. 5. 5、疑问