在项目开发过程导出Excel为常用功能,之前的一篇Java导出超大Excel文件,防止内存溢出已经解决了Excel写入层面时的内存问题,但数据库查询层面,仍存在由于默认的mybatis查询是将所有数据都查询到本地内存,因此仍有可能会导致内存溢出,因此本文再详细介绍记录通过mybatis的ResultHander进行流式查询读取
来完全解决excel的大量数据导出内存溢出问题。
一.先批量插入测试数据
1.建表,包含2个字段username,age
1 | c复制代码CREATE TABLE `t_user` ( |
2.UserMapper.xml
1 | c复制代码 <insert id="batchInsert"> |
3.UserMapper.java
1 | c复制代码int batchInsert(List<User> list); |
4.UserService.java & UserServiceImpl.java
1 | c复制代码int batchInsert(List<User> list); |
5.UserController.java中编写测试代码,写入100万行数据
1 | c复制代码 //1.插入1000101行测试数据 |
二、ResultHandler流式查询导出
ResultHandler接口可以用于进行流式查询(
即一行一行从数据库中读取处理,因此不会占用本地内存
),本文的核心就是通过调用mapper的方法,传入一个ResultHandler
,然后在实现的方法中读取数据,然后一行一行处理。
1.在UserMapper.xml中配置
其中的resultSetType为FORWARD_ONLY,fetchSize为-2147483648
1 | c复制代码 <sql id="listSql"> |
2.UserMapper.java中编写方法
1 | c复制代码 /**导出,mapper的方法需要是void返回,并且参数中含ResultHandler(流式查询遍历的条件),这里我没加参数,可以加上你的条件参数*/ |
重要注意点:要满足流式查询,需要方法返回值为void,并且方法中有ResultHandler类型的参数。
在mybatis源码中的MapperMethod.java中也能看到对应的代码判断如下:
3.自定义一个ExcelResultHandler,提供给所有导出的代码共用
此ResultHandler实现了excel的导出,并遍历mapper查询数据,一行一行写入excel,节省内存,可以在导出的业务代码进行使用,具有通用性,只需要new出对象然后调用相应的方法。
1 | c复制代码package cn.gzsendi.modules.framework.utils; |
4.在UserServiceImpl实现类中进行ExcelResultHandler的调用并写入excel,如下:
1 | c复制代码 /**导出*/ |
说明:
UserServiceImpl类的导出代码中,只需要new一个ExcelResultHandler,然后实现其抽象方法tryFetchDataAndWriteToExcel(),在tryFetchDataAndWriteToExcel方法中进行mapper的方法调用,传递一个ResultHander对象,如上面代码中的userMapper.export(this),new完ExcelResultHandler对象时,导出还没有开始,执行handler.startExportExcel()才进行真正的导出功能
,先拿到输出流,然后设置好excel的表头,并写入表头,然后调用tryFetchDataAndWriteToExcel方法,在tryFetchDataAndWriteToExcel方法中会调用mybatis的mapper的方法,在mybatis的mapper的方法中遍历所有的数据,然后一行一行写入excel
,最终关闭资源流等,如下:`
1 | c复制代码 public void handleResult(ResultContext<? extends T> resultContext) { |
4.测试结果截图如下:
输入http://localhost:8080/test/user/export进行导出测试
三、源码demo下载
详细源码附件如下:可直接下载进行测试
github: github.com/jxlhljh/spr…
gitee: gitee.com/jxlhljh/spr…
本文转载自: 掘金