1.SXSSFWorkbook理解:
SXSSFWorkbook是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excel,SXSSFWorkbook专门处理大数据,对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了。它的原理很简单,用硬盘空间换内存(就像hashmap用空间换时间一样)。 SXSSFWorkbook是streaming版本的XSSFWorkbook,它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到硬盘里(Windows电脑的话,是写入到C盘根目录下的temp文件夹)。被写入到硬盘里的rows是不可见的/不可访问的。只有还保存在内存里的才可以被访问到。
注:HSSFWorkbook和XSSFWorkbook的Excel Sheet导出条数上限(<=2003版)是65535行、256列,(>=2007版)是1048576行,16384列,如果数据量超过了此上限,那么可以使用SXSSFWorkbook来导出。实际上上万条数据,甚至上千条数据就可以考虑使用SXSSFWorkbook了。
注意:首先需要引入依赖:注意:4.0.0版本的JDK需要1.8以上,如果JDK是1.7的,那么就使用3.9版本的依赖
2.数据过多使用SXSSFWorkbook也是会出现内存溢出的问题,主要出现的两个地方:
a.从数据库读取数据到内存时溢出。
优化角度1:取数据时用分页的方法分批取数据,然后写入sheet中。这样就可以避免取数据时内存溢出;
java.lang.OutOfMemoryError:GC overhead limit exceeded
b.FileOutputStream os = new FileOutputStream(path); wb.write(os);
优化角度2: 创建Workbook时设置工作簿保存在内存中数据的条数,这样一旦这个Workbook中数据量超过1000就会写入到磁盘中,减少内存的使用量来提高速度和避免溢出。
Workbook wb = new SXSSFWorkbook(1000);
3.通过分页查询实现海量excle数据的导出,避免发生OOM。代码如下:
@RequestMapping("/exportPurchaseInfo.do") @ResponseBody public void exportPurchaseGoodsInfo(HttpServletRequest request, HttpServletResponse response,QueryParamDto reqDto) { try { int pageSize = 1000;//分页的大小,即每次分页查询多少条记录开关 String[] headers = {"序号","商品编号","商品名称","品类","品牌","采购金额(元)","采购数量(件)"}; SXSSFWorkbook workbook = ExportExcelByPageUtil.makeSXSSFWorkbook(purchseReportExportExcelByPageService,reqDto, headers, pageSize); ExportExcelByPageUtil.exportExcel(request, response, workbook, "商品销售报表.xlsx"); } catch (Exception e) { logger.error("导出商品销售报表异常",e); } }
ExportExcelByPageUtil.java
public static <T> SXSSFWorkbook makeSXSSFWorkbook(ReportExportExcelByPageService<T> exportExcelByPageTyService, T queryDataBo, String[] headers, int pageSize){ int rowAccessWindowSize = 100; //这样表示SXSSFWorkbook只会保留100条数据在内存中,其它的数据都会写到磁盘里,这样的话占用的内存就会很少 SXSSFWorkbook workbook = new SXSSFWorkbook(rowAccessWindowSize); SXSSFSheet sheet = (SXSSFSheet) workbook.createSheet("sheet1"); Map<String,CellStyle> cellStyles=getCellStyle(workbook); CellStyle cs = cellStyles.get("cs"); CellStyle cs2 = cellStyles.get("cs2"); //设置列名 Row row = sheet.createRow((short) 0); for (int i = 0; i < headers.length; i++) { Cell cell = row.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(cs); } String pattern = "yyyy-MM-dd HH:mm:ss"; String beginTime = DateUtil.formatDate(new Date(), pattern); int allCount = exportExcelByPageTyService.queryAllCount(queryDataBo); if(allCount <= 0){ return workbook; } //处理数据量超过一个sheet页最大量时异常,支持的最大导出数据量为10000 int maxExportCount = 10000;