easypoi 导出大数据量数据内存溢出问题

 问题描述:

       正常我们用框架生成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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值