天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

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

itzoo 464次浏览 0个评论

点击“终码一生”,关注,置顶公众号

每日技术干货,第一时间送达!



今天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


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


 

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


PS:防止找不到本篇文章,可以收藏点赞,方便翻阅查找哦。


往期推荐



IntelliJ IDEA中的神仙插件 写代码必备!

强大的集合工具类,java.util.Collections中未包含的集合工具

推荐2个Springboot的工作流项目,轻松搞定工作流!

SpringBoot 如何统计、监控 SQL运行情况?

为什么要尽量避免使用 IN 和 NOT IN 呢?

什么是流式SQL,它有什么用?



ITZOO版权所有丨如未注明 , 均为原创丨转载请注明来自IT乐园 ->MyBatis中使用流式查询避免数据量过大导致OOM
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址