导出数据是一个应用常用的功能,而使用java语言时常用的工具类莫过于POI。不过当数据量很大时,会经常遇到OOM的问题。我们在项目中有时会几万,几十万,几百万的数据进行导出,这个时候很容易就会导致内存溢出。
我们可以按以下方法进行优化处理:
一、我们导出数据时,常常是将数据一次性全部加载到内存中来,进行数据处理和导出,这样很容易导致OOM,我们可以对大文件拆分成小文件进行保存,最后对所有临时文件进行打包导出或者对小文件进行merge。不过merge文件的过程注定是一个消耗时间的过程,因为需要打开多个小文件再进行合并,虽然导出文件不再OOm,但是可能会导致超时,此时我们可以进行第二步
二、经过了解在POI中除了HSSWorkbook和XSSFWorkbook之外,还有一个SXSSFWorkbook,该类通过设置rowAccessWindowSize参数,可以调整保存在内存中的对象数量,大于rowAcessWindowSize的数据会缓存到磁盘上。通常缓存的文件大小会比结果大,如果磁盘空间有限,可以通过setCompressTempFiles参数进行文件压缩(不过压缩会消耗部分性能,实际情况综合取舍)。通过分页加载数据到SXSSFWorkbook中的方式避免了全量数据加载内存导致内存溢出的情况,但是当数据量巨大时,还是推荐可以将文件进行拆分,否则还是会遇到超时的情况。
三、我们在查询一个表数据的时候,往往把表中的所有字段都查询出来了,有些表结构比较大的可能有100,200个字段,但是我们在实际导出excel的时候用的字段不超过10个,这样使用的内存将减少10倍左右,那我们就没有必要去查询出这么多字段,建立一个vo,查询出我们需要的字段,然后进行数据处理和导出。
四、我们将下载改为异步下载,通过邮件的方式发送,可以解决超大数据导出超时问题。