一、传统形式上进行百万导出


依据后面咱们的形式解决百万导出,那么就要做百万次循环

//1.结构数据,假如有百万数据List<User> list = userService.findByReport(companyId,month+"%");//2.创立工作簿XSSFWorkbook workbook = new XSSFWorkbook();//3.结构sheetSheet sheet = workbook.createSheet();Row row = sheet.createRow(0);int titleInext = 0;Cell cell = null;//4.写入单元格for (user report : list) {    Row dataRow = sheet.createRow(titleInext++);    //编号    cell = dataRow.createCell(0);    cell.setCellValue(report.getUserId());    //姓名    cell = dataRow.createCell(1);    cell.setCellValue(report.getUsername());    //手机    cell = dataRow.createCell(2);    cell.setCellValue(report.getMobile());}    

如果是基于XSSFWorkbook报表导出,那么咱们在Jvisualvm看看效率

应用传统的形式去解决百万数据,会一直的占用内存,直到吃满跑出oom异样

那么为什么会这样呢?

二、传统形式上问题剖析


那么为什么会占用那么多内存呢?

首先咱们row、cell单元格、cell款式等等都是一个对象

当咱们excel导出而言,是将所有对象都创立进去放入内存中,所有的对象都加载实现后,在以流的形式进行加载下载进去

也就是说下载之前咱们的对象始终在占有中,没有被开释,所以占用字节十分的大

对于百万数据量的Excel导入导出,只探讨基于Excel2007的解决办法。

在ApachePoi 官网提供了对操作大数据量的导入导出的工具和解决办法,操作Excel2007应用XSSF对象,能够分为三种模式:

  • 用户模式:用户模式有许多封装好的办法操作简略,但创立太多的对象,十分耗内存(之前应用的办法)
  • 事件模式:基于SAX形式解析XML,SAX全称Simple API for XML,它是一个接口,也是一个软件包。它是一种XML解析的代替办法,不同于DOM解析XML文档时把所有内容一次性加载到内存中的形式,它逐行扫描文档,一边扫描,一边解析
  • SXSSF对象:是用来生成海量excel数据文件,次要原理是借助长期存储空间生成excel

Apache POI官网提供有一张图片,形容了基于用户模式,事件模式,以及应用SXSSF三种形式操作Excel的个性以及CUP和内存占用状况

三、解决思路剖析


咱们刚刚进行问题剖析晓得基于XSSFWork导出Excel报表,是通过将所有单元格对象保留到内存中,当所有的Excel单元格全副创立实现之后
一次性写入到Excel并导出。

当百万数据级别的Excel导出时,随着表格的一直创立,内存中对象越来越多,直至内存溢出。

以及咱们说到Apache Poi提供了SXSSFWork对象,专门用于解决大数据量Excel报表导出。

那么为什么应用SXSSFWork对象就能够解决这个问题呢?

SXSSFWork原理剖析

在实例化SXSSFWork这个对象时,能够指定在内存中所产生的POI导出相干对象的数量(默认100)。

一旦内存中的对象的个数达到这个指定值时,就将内存中的这些对象的内容写入到磁盘中(XML的文件格式)。

再将这些对象从内存中销毁,当前只有达到这个值,就会以相似的解决形式解决,直至Excel导出实现。

四、应用SXSSFWork优化传统形式


接下来咱们应用SXSSFWork对象优化传统形式上的有余

//1.结构数据,假如有百万数据List<User> list = userService.findByReport(companyId,month+"%");//2.创立工作簿//能够在括号里写阈值默认为100,即内存中的对象数量最大数量SXSSFWorkbook workbook = new SXSSFWorkbook();//3.结构sheetSheet sheet = workbook.createSheet();Cell cell = null;//4.写入单元格for (user report : list) {    Row dataRow = sheet.createRow(titleInext++);    //编号    cell = dataRow.createCell(0);    cell.setCellValue(report.getUserId());    //姓名    cell = dataRow.createCell(1);    cell.setCellValue(report.getUsername());    //手机    cell = dataRow.createCell(2);    cell.setCellValue(report.getMobile());} 

接下来咱们应用SXSSFWorkbook生成Excel报表的形式看看Jvisualvm

这时咱们发现蓝色的中央有点挫折,这是因为将对象写入了磁盘里

所以会先上坡再下坡,然而他的效率相比传统形式占用字节少了很多很多

五、总结


当咱们采纳SXSSFWorkbook形式的时候会发现他会转为xml的长期形式进行放入硬盘文件

即便咱们是通过临时文件的模式放入硬盘中,也会呈现有撑爆的危险

因为咱们是先放入内存中,再从内存中转入硬盘文件

对于传统的形式,咱们能够采纳SXSSFWorkbook来做,但它不是万能的还须要缩小对象的产生,比如说款式、字体等

参考资料


黑马程序员:基于SaaS平台的iHRM刷脸登录实战开发(报表相干视频)