目录
一、简介
在上篇文章《Springboot导出大数据量excel》说道查询数据量过大的时候还没到导出的时候就会导致内存溢出(或者占用服务较大内存)的问题。本文内容主要就是解决这个问题。
注意:excel的有最大支持数据行数1048576(2的20次方),超出会报异常:
{"code":500,"msg":"fail","data":"Invalid row number (1048576) outside allowable range (0..1048575)"}
解决方案:
方案一:
根据实际情况拆分成多个excel的压缩包。
方案二:
使用csv(使用wps打开只能看到1048576数据,使用文本工具打开能看到全部数据)。
参考:《Springboot导出大数据量excel(三)-导出csv到压缩包》
二、测试
使用poi框架实现大数量导出测试:
1导出100万行数据测试
jdk 1.8
easypoi 4.4.0
springboot 2.3.0
jvm -Xms128m -Xmx256m
api | 结果 | 耗时 | 文件大小 |
ExcelUtil.exportBigExcel | 内存溢出 | 62s | 31.3M |
ExcelUtil.exportExcel | 内存溢出 | - |
2exportExcel堆内存
内存溢出
3exportBigExcel堆内存
三、关键代码
controller
@RequestMapping(value = "export3", method = RequestMethod.GET)
@ApiOperation(value = "导出大量数据(Map)", notes = "SXSSFWorkbook")
@ApiImplicitParams({})
public void export3(HttpServletResponse response, HttpServletRequest request) throws Exception {
Workbook workbook = null;
Date start = new Date();
Map<String, Object> params = new HashMap<>();
params.put("pageSize", 5000);
workbook = ExcelUtil.exportBigExcel(params, (param, page) -> {
param.put("pageNum", page);
//模拟分页查询数据
List<Map<String, Object>> list = getPageData2(param);
return list;
});
downLoadExcel("test" + System.currentTimeMillis() + ".xlsx", response, workbook);
System.out.println(new Date().getTime() - start.getTime());
workbook.close();
}
ExcelUtil
public static SXSSFWorkbook exportBigExcel(Map<String, Object> queryParams, MyExcelExportServer server) {
//这样表示SXSSFWorkbook只会保留100条数据在内存中,其它的数据都会写到磁盘里,这样的话占用的内存就会很少
SXSSFWorkbook workbook = new SXSSFWorkbook(100);
//创建Excel的sheet
SXSSFSheet sheet = workbook.createSheet("sheet1");
//从list取第一行到最后一行的内容并放到对应的Excel里,若记录里某字段值没有会有问题
int rowNum = 0;//行数
int page = 1;
int var6 = page + 1;
for (List<Map<String, Object>> list = server.selectListForExcelExport(queryParams, page); list != null && list.size() > 0; list = server.selectListForExcelExport(queryParams, var6++)) {
if (rowNum == 0) {
//设置表头
int n = 0;//列数
Map<String, Object> map = list.get(0);
SXSSFRow first = sheet.createRow(0);//创建sheet的第一行
for (String key : map.keySet()) {
//创建单元格并赋值
first.createCell(n).setCellValue(key);
n++;
}
rowNum++;
}
for (Map<String, Object> data : list) {
SXSSFRow row = sheet.createRow(rowNum);//创建sheet的第rownum+1行
int n = 0;//列数
for (String key : data.keySet()) {
row.createCell(n).setCellValue(data.get(key) != null ? data.get(key).toString() : "");
n++;
}
rowNum++;
}
}
return workbook;
}