一、传统形式上进行百万导出
依据后面咱们的形式解决百万导出,那么就要做百万次循环
//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刷脸登录实战开发(报表相干视频)