JAVA OutOfMemoryError问题使用Excel在Apache POI Stream API中导出150K +数据

时间:2018-05-31 07:53:30

标签: java apache-poi

我的Apache POI版本是3.14。我想将大数据导出到excel?为此,我在互联网上找到了this解决方案并实施了它。

所以,我有以下List来自我的数据库(PostgresSQL):

List<TransactionDTO> result = new ArrayList<>(); result.addAll(transactionService.findByInDateRange(status, fromDate, toDate));

然后我按照上面提到的链接(逻辑完全一样)。

   DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_hh_mm_ss");
    String excelFileName = "Statistics_by_partner" + formatter.format(LocalDateTime.now()) + ".xlsx";
    SXSSFWorkbook wb = (new ExportRevisionResponseExcel()).exportExcel(new String[] { "Status",
        "Request",}, result);
    try {
        ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
        wb.write(outByteStream);
        byte[] outArray = outByteStream.toByteArray();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setContentLength(outArray.length);
        response.setHeader("Expires:", "0"); // eliminates browser caching
        response.setHeader("Content-Disposition", "attachment; filename=" + excelFileName);
        OutputStream outStream = response.getOutputStream();
        outStream.write(outArray);
        outStream.flush();
        wb.dispose();
        wb.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }`

然而,它仍然给我内存错误。

顺便说一下,我不认为增加JAVA堆内存是个好主意。

1 个答案:

答案 0 :(得分:4)

您用尽堆空间的最可能原因是您将整个工作簿流流式传输到内存中的字节数组缓冲区。

    ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
    wb.write(outByteStream);

这可以消耗最多三倍 1 实际流长度(以字节为单位)。如果要使用更少的内存,请将数据直接写入响应流:

    OutputStream outStream = response.getOutputStream();
    wb.write(outStream);

显然,这意味着您将无法在响应中设置内容长度。如果这对您来说非常重要,那么使用临时文件缓冲数据而不是ByteArrayOutputStream

1 - BAOS使用内部byte[]作为缓冲区。当缓冲区已满时,它会分配两倍大小的新缓冲区,并将旧数据库中的数据复制到新缓冲区。当你进行复制时,你有2个字节的数组,占到目前为止缓冲的字节数的3倍。

相关问题