问题描述:

       正常我们用框架生成excel 表的时候,导出表格很丝滑,没有什么问题。但是随着系统数据的增大。导出的数据越来越多,如果一次性load到内存中,根据垃圾回收机制,大对象可能直接进入老年代存储,所以很有可能会引发频繁的fullgc 问题。如果jvm 设置的内存太小的话,可能直接导致内存溢出的问题。所以当业务数据不断变多的过程,之前没有引发的性能问题也逐渐暴露出来。

       今天就看看改造对应的easypoi 的导出。

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>4.0.0</version>
</dependency>

改造过程:明确改造的问题点:

      1.解决数据量过大导致,内存溢出问题

      2.同步导出,由于网关对请求超时熔断,导致导出失败问题

针对第一个问题:

      1.考虑批量的方式,分批导出数据库中的信息,通过重复指向不同的堆对象,及时释放内存,保证只占用一次循环的最大内存。

      2.调用easypoi自带的导出大数据量的方法,分批导出后合并成一个sheet 导出。可参考easypoi大批量导出(二)

for (int i = 0; i < remoteCount; i++) {
    //组装导出信息
    List<ContractExcelVO> contractExcelVOS = new ArrayList<>();
    int end = (i + 1) * sheetCount < contractIds.size() ? (i + 1) * sheetCount : contractIds.size();
    List<Long> contractIdSubList = new ArrayList<>(contractIds.subList(i * sheetCount, end));
    //组装你的表格主体内容
    ExportParams exportParams = new ExportParams();
    exportParams.setType(ExcelType.XSSF);
    exportParams.setTitle("合同信息");
    exportParams.setSheetName("合同信息_"+i);
    //导出多个表格
    workbook = ExcelExportUtil.exportBigExcel(exportParams, ContractExcelVO.class, contractExcelVOS);
}

第二个问题的解决思路:

      1.设计一个导入任务记录表。在用户执行导出动作的时候就要插入一个任务。

      2.导出的主体实现开启另外一个线程,采用异步导出。

      3. 将生成的excel 文件上传到阿里云的oss 服务中,再将oss 返回的下载地址插入到任务记录表中,提供用户下载。

ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 创建字节数组输出流
try {
    workbook.write(bos); // 将Workbook写入字节数组输出流
} catch (IOException e) {
    log.info("将Workbook写入字节数组输出流失败", e);
    throw new RuntimeException(e);
}
byte[] bytes = bos.toByteArray(); // 将输出流转换为字节数组
InputStream inputStream = new ByteArrayInputStream(bytes); // 创建字节数组输入流
String uploadFileName = System.currentTimeMillis() + "contractInfo.xlsx";
String absoluteUrl = ossUtil.uploadOss(uploadFileName, inputStream);
if (StringUtils.isEmpty(absoluteUrl)) {
    contractExportTaskInfo.setTaskStatus(TaskStatusEnum.FAIL.getIndex());
    contractExportTaskInfo.setTaskDesc("上传文件到阿里云失败");
    contractExportTaskInfoService.updateById(contractExportTaskInfo);
    return;
}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐