easyexcel导出100w条数据,使用分页查询批量导入

昨天公司的数据那边的人导出操作日志,一次性导出30w+让服务直接挂掉了,所有有了这篇文章...

正常从数据库导出少量数据到execl,直接将符合条件的数据全部查询放到一个List中然后写到execl里即可,但是数据量过大时会导致内存兜不住的情况.

解决思路就是:一次性查询1w条数据加载到内存中,然后将这1w条数据写到execl里,再使用分页查询下一批1w的数据...实现如下:

@PostMapping("/operationLog")
    public void operationLog(HttpServletResponse response, @RequestBody Dashboard dashboard) throws IOException {
        String fileName = URLEncoder.encode("操作日志", "UTF-8").replaceAll("\\+", "%20");//设置文件名
        String ymds = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ymds + ".xlsx");//设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //设置响应内容类型
        response.setCharacterEncoding("utf-8");//编码

        ExcelWriter writer = EasyExcel.write(response.getOutputStream(), OparationExcel.class).build();
        WriteSheet sheet = EasyExcel.writerSheet("操作日志").build();

        Page<OparationExcel> page = dashboardFeign.operationLogPage(1L, 10000L, dashboard);
        long total = page.getTotal();
        if (total <= 10000) {
            writer.write(page.getRecords(), sheet);
            writer.finish();//关闭流
            return;
        }
//        excelWriter.write(page.getRecords(), writeSheet);
        int ceil = (int) Math.ceil(NumberUtil.div(total, 10000L));
        for (int i = 1; i <= ceil; i++) {
            page.setCurrent(i);
            page = dashboardFeign.operationLogPage((long) i, 10000L, dashboard);
            writer.write(page.getRecords(), sheet);
        }
        writer.finish();//关闭流
    }

注意!!!:我这里使用的分页是mybatisplus提供的分页功能,有一个小小的问题需要注意的,mybatisplus的分页参数size,最大值为500,如果需要打破这个限制,需要自己写一个

MybatisPlusConfig继承MetaObjectHandler接口并重写paginationInterceptor方法,实现如下:
@Bean
public PaginationInterceptor paginationInterceptor() {
    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    // 设置最大单页限制数量,默认 500 条,-1 不受限制
    paginationInterceptor.setLimit(-1);
    return paginationInterceptor;
}

另外一个思路就是自己用查询页码(current)和每页数量(size)计算limit的两个值,手写SQL,都是很简单的实现.

另外一点,我这是是将所有数据都写到一个工作簿(sheet)当中,如果你希望分开写,只需要将sheet在循环中创建即可,EasyExcel.writerSheet()可传两个参数,第一个是索引(Integer),第二个是名称(String),

这也是基本实现需要,能导出大量数据,服务也不会挂,还有很多可以优化的地方,比如一次性写两万或者更多,具体看你们的服务器咋样,我们没有做这个测试所以选择牺牲效率,还有一点优化的地方(想到了但是我没做),这个逻辑是读出来然后写进execl,其实在写的时候我们就可以去查询下一次的数据加载到内存或者Redis中,而不需要写完之后再去查.

刚毕业还在实习,有问题希望大佬指正,感谢!!!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值