使用 Mybatis-plus 的 ResultHandler 配合 EasyExcel 导出万条记录
使用 Mybatis-plus 的 ResultHandler 配合 EasyExcel 导出万条记录
前言
最近工作遇到的问题,就是需要导出每个月的订单列表。订单需要关联用户信息,商品信息,上下级关系(涉及分佣)等其他表。一开始用的常规支持的包 POI,数据一多就会报 OOM内存溢出的错误。后改用阿里的 easyexcel 包。官方文档:→ EasyExcel,例子很多,可以慢慢研究下。代码写完后测试,发现几百条的数据导出需要 10s 左右,有点蒙!!!然后继续导出2000条数据,结果竟然崩掉了!错误提示:你的主机关闭了一个连接...
解决
遇到问题,先分析原因所在。首先我从 SQL 语句着手,优化语句。先给关联字段加上索引,查询具体字段代替 * ,使用 Mysql 的 EXPLAIN 关键字分析 SQL 是否命中索引。单独复制语句到数据库工具中查询,发现按月查询一万多条数据可以 300 毫秒内查出,那语句这一块就算解决了。先看看初期的代码实现:
public void exports(HttpServletResponse response, ServletRequest request) throws InterruptedException {
long start = System.currentTimeMillis();
Map<String, Object> params = searchCondition(request);
List<OrderVo> orderList = orderService.getOrderList(params);
System.out.println("本次查询用时: " + (end - start));
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 防止中文乱码
String fileName = null;
try {
fileName = URLEncoder.encode("订单", "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
try {
EasyExcel.write(response.getOutputStream(), OrderExportVo.class).sheet("订单").doWrite(orderList);
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("本次导出用时: " + (end - start));
}
以上导出 5000 条数据以内,基本稳定在 10s 内,我还是不太能接收,因为数据可能上万条的,这样导出可能都需要 30s 起步了。于是继续寻找解决方案,无意间看到几个关键字:导出百万数据,看了下别人的解决方案,就是使用 mybatis 的 ResultHandler 流查询,配合 EasyExcel 的使用。话不多说先上代码:
public void exportOrder(HttpServletResponse response, ServletRequest request) throws IOException {
ExcelWriter excelWriter = null;
try {
// 防止中文乱码
String fileName = URLEncoder.encode("订单", "UTF-8");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
excelWriter = EasyExcel.write(response.getOutputStream(), OrderExportVo.class).build();
WriteSheet sheet = EasyExcel.writerSheet("订单").build();
ArrayList<OrderExportVo> arr = new ArrayList<>(1);
ExcelWriter finalExcelWriter = excelWriter;
orderService.selectOrderList(params, resultContext -> {
orderVo orderVo = resultContext.getResultObject();
OrderExportVo order = new OrderExportVo();
order.setOrderNo(orderVo.getOrderNo());
order.setCreateDate(orderVo.getCreateDate());
// ...
arr.add(order);
finalExcelWriter.write(arr, sheet);
arr.clear();
});
} catch (UnsupportedEncodingException e) {
log.info("订单导出错误: " + e.getMessage());
} finally {
if (null != excelWriter) {
excelWriter.finish();
}
}
long end = System.currentTimeMillis();
System.out.println("本次导出用时: " + (end - start));
}
然后就是测试了,导出 15000 条数据,用时:3507毫秒,我惊了!!!----勉强能用。
最后补充:
我使用的是 Mybatis-plus 需要在配置文件里设置如下:
mybatis-plus.configuration.safe-result-handler-enabled=false
写在最后,写博客只是当做个笔记,写的内容也仅限于本人理解。如果你看到了有什么疑惑可以留言咨询,其他不懂的可以继续搜索相关资料。

浙公网安备 33010602011771号