java导出百万级数据到excel
java导出百万级数据到excel
最近修改了⼀个导出员⼯培训课程的历史记录(⼀年数据),导出功能本来就有的,不过前台做了时间限制(只能选择⼀个⽉时间内的),还有⼀些必选条件,导出的数据⾮常有局限性。⼼想:为什么要做出这么多条件限制呢?条件限制⽆所谓了,能限制导出数据的准确性,但是时间?如果我想导出⼀年的数据,还要⼀⽉⼀⽉的去导出,这也太扯了。于是我试着放开时间js限制,让⽤户⾃⼰随便选好了,然后⾃⼰选了⼀段时间,选了⼏门课程,点击按钮导出,MD报错了,看后台⽇志说什么IO流报异常,看了下代码,代码也很简单,查询数据,⽤HSSFWorkbook 写⼊数据,关闭流,导出,似乎没什么问题。于是去把查询的sql拉出来,放⼊数据库,查询数据,20w条数据,好吧,这下终于知道为什么加时间限制了,数据量过
⼤程序处理不了,改代码吧。虽说实际⼯作中很少有百万数据导⼊excel,但不缺少⼀些会excel的⾼⼿,分析对⽐数据,像我这种⼿残党是不⾏,他们怎么⽤暂时不⽤管,能不能实现,就是我们应该考虑的事了。
此案例能解决2个问题:
1.⽤户导出速度过慢
2.采⽤分页导出,以解决单个sheet页数据量过⼤,打开速度过慢
简单介绍下我的操作:
HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls,⼀张表最⼤⽀持65536⾏数据,256列,也就是说⼀个sheet页,最多导出6w多条数据
XSSFWorkbook:是操作Excel2007-2010的版本,扩展名是.xlsx对于不同版本的EXCEL⽂档要使⽤不同的⼯具类,如果使⽤错了,
会提⽰如下错误信息。
org.apache.ptions.InvalidOperationException
org.apache.poi.poifs.filesystem.OfficeXmlFileException
它的⼀张表最⼤⽀持1048576⾏,16384列,关于两者介绍,对下⾯导出百万数据很重要,不要使⽤错了!
2.
SXSSFWorkbook使⽤⽅法和 HSSFWorkbook差不多,如果你之前和我⼀样⽤的HSSFWorkbook,现
在想要修改,则只需要将HSSFWorkbook改成SXSSFWorkbook即可,下⾯有我介绍,具体使⽤也可参考。
3.
导出百万数据到excel,很简单,只需要将原来的HSSFWorkbook修改成SXSSFWorkbook,或者直接使⽤SXSSFWorkbook对象,它是直接⽤来导出⼤数据⽤的,有介绍,但是如果有300w条数据,⼀下导⼊⼀个excel的sheet页中,想想打开excel也需要⼀段时间吧,慢的话有可能导致程序⽆法加载,或者直接结束进程的情况发⽣,曾看到过⼀段,这⾥对⽼外的毅⼒也是深表佩服。
这⾥给出部分代码,供参考研究,分页已实现:
@SuppressWarnings({ "deprecation", "unchecked" })
@RequestMapping("export-TrainHistoryRecord")
@ResponseBody
protected void buildExcelDocument(EmployeeTrainHistoryQuery query,ModelMap model,
SXSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
try {
// 获得国际化语⾔
RequestContext requestContext = new RequestContext(request);
String CourseCompany = requestContext
.getMessage("manage-student-trainRecods");
response.setContentType("APPLICATION/vnd.ms-excel;charset=UTF-8");
// 注意,如果去掉下⾯⼀⾏代码中的attachment; 那么也会使IE⾃动打开⽂件。
response.setHeader(
"Content-Disposition",
"attachment; filename="
+ de(
OutputStream os = OutputStream();
CellStyle style = ateCellStyle();
// 设置样式
style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);//设置单元格着⾊
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);  //设置单元格填充样式
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);//设置下边框
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);//设置左边框
style.setBorderRight(HSSFCellStyle.BORDER_THIN);//设置右边框
style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 居中
//获取国际化⽂件
String employeeCode = Message("employeeCode");
String employeeName = Message("employeeName");
String orgName = Message("orgName");
String startDate = Message("start.date");
String endDate = Message("end.date");
String courseCode = Message("courseCode");
String courseName = Message("courseName");
String sessionName = Message("sessionName");
List<EmployeeTrainHistoryModel> list = null;
try {
//查询数据库中共有多少条数据
query.setTotalItem(employeeTrainHistoryService.fetchCountEmployeeTrainHistoryByQuery(query));
int page_size = 100000;// 定义每页数据数量
int list_count =TotalItem();
//总数量除以每页显⽰条数等于页数
戈伟如金城武
int export_times = list_count % page_size > 0 ? list_count / page_size
+ 1 : list_count / page_size;
//循环获取产⽣每页数据
for (int m = 0; m < export_times; m++) {
query.setNeedQueryAll(false);
query.setPageSize(100000);//每页显⽰多少条数据
query.setCurrentPage(m+1);//设置第⼏页
EmployeeTrainHistoryByQuery(query);
//新建sheet
Sheet sheet = null;
sheet = ateSheet(System.currentTimeMillis()
+ CourseCompany+m);
// 创建属于上⾯Sheet的Row,参数0可以是0~65535之间的任何⼀个,
Row header = ateRow(0); // 第0⾏
// 产⽣标题列,每个sheet页产⽣⼀个标题
Cell cell;
String[] headerArr = new String[] { employeeCode, employeeName,
orgName, startDate, endDate, courseCode, courseName, sessionName,
hoursNunber };
for (int j = 0; j < headerArr.length; j++) {
cell = ateCell((short) j);
cell.setCellStyle(style);
cell.setCellValue(headerArr[j]);
}
// 迭代数据
if (list != null && list.size() > 0) {
int rowNum = 1;
for (int i = 0; i < list.size(); i++) {
EmployeeTrainHistoryModel (i);
sheet.setDefaultColumnWidth((short) 17);
Row row = ateRow(rowNum++);
.OrgName());
if (TrainBeginTime() != null) {
} else {
}
if (TrainEndTime() != null) {
ie浏览器怎么卸载
} else {
}
if (HoursNumber() != null)
}
}
list.clear();
}
} catch (Exception e) {
e.printStackTrace();江南水乡古镇
}
吉他换弦try {
workbook.write(os);
os.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
4.
第3部分,⼤数据量导出数据,分页都已实现,但怎样才能去压榨时间,⾼效导出?Apache POI既然提供了导出excel的⽅法,想必也考虑到了效率问题,查看,果不其然,看⽂档,⼤概意思就是说SXSSF在必须⽣成⼤型电⼦表格时使⽤,堆空间有限官⽅提供了2种⽅法:母亲节祝词
1.  SXSSFWorkbook wb = new SXSSFWorkbook(100);  // keep 100 rows in memory, exceeding rows will be flushed to disk
2.SXSSFWorkbook wb = new SXSSFWorkbook(-1);  // turn off auto-flushing and accumulate all rows in memory
值100  在内存中保留100⾏,超过⾏将被刷新到磁盘
值-1表⽰⽆限制访问。在这种情况下所有,没有被调⽤flush()刷新的记录可⽤,⽤于随机访问。
⽂章在最后说,当临时⽂件过⼤时,可使⽤setCompressTempFiles⽅法进⾏压缩,
石家庄婚纱照哪拍的好⽐较贪⼼,这⾥我⽤了两个,⼀个⽤来设置临时⽂件,另⼀个⽤来输⼊数据,测试数据为30w数据,结果如图,不过还是感觉花费时间太多,不知道是不是我的程序写的有问题,知道的⼩伙伴,留个⾔吧!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。