Aurora?????????????SXSSFWorkbook???????Excel???

2020-12-29 16:47:32by koyoso

如何使用SXSSFWorkbook支持百万级数据Excel导出

问题背景

1. 当系统用户大量并发操作大数据量Excel导出时,致使Tomcat内存溢出(OOM)导致系统宕机。

2. 项目客户不同意使用轻量级文本txt和csv格式导出,只能用Excel。

3. 当前Aurora框架因采用XSSFWorkbook方式,在页面查询效率低和大数据情况下,极其消耗内存,难以支持百万级数据导出。

原因分析

Aurora框架Excel导出方法分为Excel2003和Excel2007。这两种方式分别运用JavaPOI中的HSSFWorkbook和XSSFWorkbook。

HSSFWorkbook是POI导出Excel最常用的方式,其对应的是Excel2003局限就是导出的行数至多为65535行,超出65536条后系统就会报错。此方式因为行数不足七万行所以一般不会发生内存不足的情况(OOM);

XSSFWorkbook的出现正是为了突破HSSFWorkbook的65535行局限。其对应的是Excel2007(1048576行,16384列)扩展名为“.xlsx”,最多可以导出104万行,不过这样就伴随着一个问题---OOM内存溢出,原因是所创建的book sheet row cell等此时是存在内存的并没有持久化。

综上可以看出以上两种方式都使用内存导出,消耗Tomcat内存。

解决方案

从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的SXSSF方式。SXSSFWorkbook的原理很简单,用硬盘空间换内存(就像hash map用空间换时间一样)。它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到硬盘里临时文件夹(Aurora框架是保存在 1#tomcat/temp/poifiles)。

具体实现

需要更改以下导出实现方法

1. 在 ../webapp/webRoot/WEB-INF/classes/aurora/plugin/poi目录下面增加ExcelExportImpl.class文件(具体文件在附件中进行下载)。目的是替换aurora.plugin.poi框架jar包中的ExcelExportImpl.class文件,修改HSSFWorkbook为SXSSFWorkbook。

headerConfig = (new MergedHeader(column_config)).conifg;
wb = new SXSSFWorkbook();
creationHelper=wb.getCreationHelper();
setCellStyle(wb);
createExcel();

2. 在 ../webapp/webRoot/WEB-INF/classes/aurora/plugin/poi目录下面增加Excel2007Bean.class文件(具体文件在附件中进行下载)。目的是替换aurora.plugin.poi框架jar包中的Excel2007Bean.class文件,修改HSSFWorkbook为SXSSFWorkbook。

import org.apache.poi.xssf.streaming.SXSSFWorkbook;
public Workbook getNewWorkbook() {
                                           return new SXSSFWorkbook();
                                              } 

3. 在 ../webapp/webRoot/WEB-INF/lib把poi-ooxml-3.13-20150929.jar包直接替换(具体文件在附件中进行下载),目的是在org.apache.poi.xssf.streaming的SXSSFWorkbook.class文件添加删除逻辑。因导出生成临时的XML文件(避免磁盘空间满),需要在导出成功后进行删除。

             finally {
                 if(!tmplFile.delete()) {
                     throw new IOException("Could not delete temporary file after processing: " + tmplFile);
                  }
              //Ing. Massimo Cavalleri - Delete tmpFiles of Sheets
              //copied from https://bz.apache.org/bugzilla/attachment.cgi?id=29018&action=edit
               for (SXSSFSheet sheet : _xFromSxHash.values()){
                  try {
                       sheet.getSheetDataWriter().finalize();
                        } catch (Throwable throwable) {
             //    throwable.printStackTrace();
                   }
                }
             }

Demo

    Comments

    0 Responses to the article

    暂时没有评论。

    发表评论