说明
导出大量数据时,虚拟机频繁GC,内存耗尽,CPU爆满
场景:java端从数据库读取100W数据进行后台业务处理
方案
可采用Mybatis数据流式读取进行优化
- 分页读取出来。缺点:需要排序后分页读取,性能低下。
- 一次性读取出来。缺点:需要很大内存,一般计算机不行。
- 建立长连接,利用服务端游标,一条一条流式返回给java端。
- jdbc中有个重要的参数fetchSize(它对业务实现无影响,即不会限制读取条数等),优化后可显著提升性能。
内容
JDBC三种读取方式:
一次全部(默认):一次获取全部。
流式:多次获取,一次一行。
游标:多次获取,一次多行。
Mapper层
<select id="exportAll" resultType="jjche.demo.modules.student.vo.StudentVO" resultSetType="FORWARD_ONLY"
fetchSize="-2147483648">
SELECT * FROM students
</select>
- Dao层
void exportAll(ResultHandler<StudentVO> handler);
- Service层
this.baseMapper.exportAll(resultContext -> {
StudentVO studentVO = resultContext.getResultObject();
list.add(studentVO);
});
原理分析
- 先在服务端执行查询后将数据缓存在服务端。(耗时相对较长)
- java端获取数据时,利用服务端游标进行指针跳动,如果fetchSize为1000,则一次性跳动1000条,返回给java端缓存起来。(耗时较短,跳动次数为N/1000)
- 在调用next函数时,优先从缓存中取数,其次执行2过程。(内存读取,耗时可忽略)