在使用mybatis列表查询时存在大数据量内存溢出的风险,这里实现了在不改变代码逻辑的情况下将查询做分页切割。点击下载资源
由定时任务跑批的数据往往使用列表直接一次性查询出来,在程序刚上线的时候可能没有问题,但是随着业务的增长我们发现原来的列表查询可能会导致内存溢出的情况。那么此时就需要考虑使用分页将原来的查询使用分页进行切割。
大家第一个想到的就是改代码,我的想法是定义一个mybatis拦截器,拦截部分mapper方法名。返回一个自定义的继承于java.util.List的PrePageList , 这个PrePageList在调用mapper的方法时返回,此时PrePageList内部是没有数据的,在后续代码中调用增强for循环时PrePageList会自动去分页查询数据。
同样的查询语句:
------------------------------------------------------------------------------------------------------------------------------
在分页切割之前是这样的:
..........
------------------------------------------------------------------------------------------------------------------------------
在使用分页切割之后是这样的:
......
使用说明:
1. 点击下载资源,解压,这里直接是一个maven工程,需要install
2. install之后,需要配置mybatis拦截器如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 全局映射器启用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 数据库超过60秒仍未响应则超时 -->
<setting name="defaultStatementTimeout" value="600" />
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<plugins>
<plugin interceptor="com.bqjr.core.util.prepage.PrePagePlugin">
<property name="dialect" value="mysql"/>
<property name="pageSize" value="3" />
<!-- 意思是以PrePage结尾的mapper方法名走分页切割框架 -->
<property name="pageSqlId" value=".*PrePage"/>
</plugin>
</plugins>
</configuration>
3.定义mapper接口(以PrePage结尾),接口在xml中的实现和正常编码一致:
public interface BusinessContractInnerMapper {
List<BusinessContractInner> getContractListPrePage(@Param("start")Date startTime, @Param("end")Date endTime,@Param("creditIdList")List<String> creditIdList);
List<BusinessContractInner> getContractList1PrePage(QueryParamDTO queryParamDTO);
List<BusinessContractInner> getContractList3PrePage(Map<String, Object> map);
List<BusinessContractInner> getContractList5PrePage();
}
4.调用时使用增强for循环遍历List做处理(不支持使用下标遍历):
@Test
public void queryContract4(){
try {
//2.执行业务
List<BusinessContractInner> contractInners = bciMapper.getContractList5PrePage();
printResult(contractInners);
} catch (Exception e) {
e.printStackTrace();
}
}
private void printResult(List<BusinessContractInner> contractInners) {
int i = 1;
//open()
for (BusinessContractInner inner : contractInners) {
//也可以做写入文件等操作
System.out.println(i+++"发送mq"+inner.getContractno());
}
//close()
}
内存分析
可以看到在读取数据的过程中,整个内存随时间得推移,使用呈现锯齿状态。符合预期
原理解释