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

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.csdn.net/bobozai86/

article/details/100033076

48e49e7fc6c032e2ef015e6b285ace24.png


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

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。

项目地址:https://github.com/YunaiV/ruoyi-vue-pro

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

基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。

项目地址:https://github.com/YunaiV/onemall

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

7c0adff855e9442c6ceecfbf1fe3efbf.png

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



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

053dfdbbf88eea333c102073056ffdbb.png

已在知识星球更新源码解析如下:

85dc32501b6b9fb86979ca8e8db17a6a.png

3ea76b2697876207603d4d5c19ee8c53.png

ff0258042c3af7bfea170c20c91f9d78.png

8dcaa733b149ef864845bc93e9e67c2f.png

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值