MyBatis中使用流式查询避免数据量过大导致OOM

Posted Java知音_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis中使用流式查询避免数据量过大导致OOM相关的知识,希望对你有一定的参考价值。

点击关注公众号,实用技术文章及时了解

今天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中配置,网上说的是这样实现:

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

参考

  • https://blog.csdn.net/weixin_43221845/article/details/84871362

  • https://www.jianshu.com/p/0339c6fe8b61

  • https://stackoverflow.com/questions/28413717/how-to-connect-a-resulthandler-in-mybatis-mapper-xml

来源:blog.csdn.net/bobozai86/article/details/100033076

推荐

主流Java进阶技术(学习资料分享)

Java面试题宝典

加入Spring技术开发社区

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

以上是关于MyBatis中使用流式查询避免数据量过大导致OOM的主要内容,如果未能解决你的问题,请参考以下文章

sql优化:数据量过大查询优化

数据量过大,导致数据库text存不下

MyBatis Plus 解决大数据量查询慢问题

sql查询未走索引问题分析之查询数据量过大

java导出excel 数据量过大 弹出excel很慢?怎么解决

Java模拟数据量过大时批量处理数据实现