关于java:我所知道报表之POI百万数据导出测试分析原理解决总结

13次阅读

共计 2387 个字符,预计需要花费 6 分钟才能阅读完成。

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


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

//1. 结构数据, 假如有百万数据
List<User> list = userService.findByReport(companyId,month+"%");
//2. 创立工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
//3. 结构 sheet
Sheet 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. 结构 sheet
Sheet 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 刷脸登录实战开发(报表相干视频)

正文完
 0