查看原文
其他

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

点击关注👉 Java后端栈 2023-09-18

推荐关注

以下文章来源Java后端栈,回复”面试“获面试宝典


哈喽,各位新来的小伙伴们,大家好!由于公众号做了改版,为了保证公众号的资源能准时推送到你手里,大家记得将后端君的公众号 加星标置顶 ,在此真诚的表示感谢~

编辑:后端妹 | 来源:blog.csdn.net/bobozai86/article/details/100033076

上一篇Java接口开发,不用写Controller、Service、Dao、Mapper、XML、VO,自动生成!



正文


大家好,我是栈哥。

今天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。另外,搜索公众号Linux就该这样学后台回复“git书籍”,获取一份惊喜礼包。

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

05、疑问

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

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


欢迎有需要的同学试试,如果本文对您有帮助,也请帮忙点个 赞 + 在看 啦!❤️ 

在 GitHub猿 还有更多优质项目系统学习资源,欢迎分享给其他同学吧!


最后给读者整理了一份BAT大厂面试真题,需要的可扫码加微信备注:“面试”获取。


◆  ◆  ◆  ◆  ◆ 

(放到你圈子里,朋友们会感激您)PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。本文仅供交流学习 , 版权归属原作者。温馨提示:《Java后端栈》推文内容如有侵权请您告知我们会在第一时间处理或撤销;互联网是一个资源共享的生态圈,我们崇尚分享。好文推荐:


欢迎添加栈哥个人微信 ysle007  进粉丝群或围观朋友圈


扫码关注带你吊爆Java后端技术

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存