思路 mybatis 流处理 (实际就是 jdbc 层面的游标,避免分页查询(只需要查询一次数据库)) + easy excel多次写。
import org.apache.ibatis.session.ResultHandler/** * 目前仅支持mybatis的流处理 * @param query 查询条件的bean * @param consumer DAO对应的查询方法 * void download(Query query, ResultHandler<OrderDownloadDO> handler); * @param excelWriter 由于分层的原因这个需要手动构造来传 * 参考构造 * ExcelWriter excelWriter = EasyExcel.write(os, OrderDownloadDTO.class).build(); * @param <T> * @param <S> */public static <T,S> void bigDataExport(T query, BiConsumer<T, ResultHandler<S>> consumer,
ExcelWriter excelWriter) {
try {
WriteSheet[] writeSheet = new WriteSheet[] {
EasyExcel.writerSheet(0, "sheet").build()
};
List<S> list = new ArrayList<>(1000);
// 0 代表当前的条数,等于100万时会被置为0
// 1 代表已经有多少个一百万
int [] c = new int[2];
consumer.accept(query, data -> {
c[0]++;
list.add(data.getResultObject());
if ((c[0] % 1000) == 0) {
excelWriter.write(list, writeSheet[0]);
list.clear();
if (c[0] == 1000000) {
c[1]++;
writeSheet[0] = EasyExcel.writerSheet(c[1], "sheet" + c[1]).build();
c[0] = 0;
}
}
});
//可能有剩余的数据
excelWriter.write(list, writeSheet[0]);
} finally {
excelWriter.finish();
}
}
XML文件写法
<select id="download" resultType="xxx.OrderDownloadDO" resultSetType="FORWARD_ONLY" fetchSize="1000"> select * from t_order </select>
调用写法
ExcelUtils.bigDataExport(query, orderDAO::download, writer);
实际测试:导出148万左右的数据(10列)只需要130秒左右,内存1g就够,并没有抛出oom。