使用 Mybatis-plus 的 ResultHandler 配合 EasyExcel 导出万条记录

使用 Mybatis-plus 的 ResultHandler 配合 EasyExcel 导出万条记录

前言

​ 最近工作遇到的问题,就是需要导出每个月的订单列表。订单需要关联用户信息,商品信息,上下级关系(涉及分佣)等其他表。一开始用的常规支持的包 POI,数据一多就会报 OOM内存溢出的错误。后改用阿里的 easyexcel 包。官方文档:→ EasyExcel,例子很多,可以慢慢研究下。代码写完后测试,发现几百条的数据导出需要 10s 左右,有点蒙!!!然后继续导出2000条数据,结果竟然崩掉了!错误提示:你的主机关闭了一个连接...

解决

​ 遇到问题,先分析原因所在。首先我从 SQL 语句着手,优化语句。先给关联字段加上索引,查询具体字段代替 * ,使用 MysqlEXPLAIN 关键字分析 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 起步了。于是继续寻找解决方案,无意间看到几个关键字:导出百万数据,看了下别人的解决方案,就是使用 mybatisResultHandler 流查询,配合 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

写在最后,写博客只是当做个笔记,写的内容也仅限于本人理解。如果你看到了有什么疑惑可以留言咨询,其他不懂的可以继续搜索相关资料。

posted @ 2021-12-31 10:59  Java-练习生  阅读(337)  评论(0)    收藏  举报