java 分页导出百万级数据到excel
最近修改了一个导出员工培训课程的历史记录(一年数据),导出功能本来就有的,不过前台做了时间限制(只能选择一个月时间内的),还有一些必选条件, 导出的数据非常有局限性。心想:为什么要做出这么多条件限制呢?条件限制无所谓了,能限制导出数据的准确性,但是时间? 如果我想导出一年的数据,还要一月一月的去导出,这也太扯了。于是我试着放开时间js限制,让用户自己随便选好了,然后自己选了一段时间,选了几门课程,点击按钮导出,MD报错了,看后台日志说什么IO流报异常,看了下代码,代码也很简单,查询数据,用HSSFWorkbook 写入数据,关闭流,导出,似乎没什么问题。于是去把查询的sql拉出来,放入数据库,查询数据,20w条数据,好吧,这下终于知道为什么加时间限制了,数据量过大!!!程序处理不了,改代码吧。 虽说实际工作中很少有百万数据导入excel,但不缺少一些会excel的高手,分析对比数据,像我这种手残党是不行,他们怎么用暂时不用管,能不能实现,就是我们应该考虑的事了。
此案例能解决2个问题:
1.用户导出速度过慢
2.采用分页导出,以解决单个sheet页数据量过大,打开速度过慢
简单介绍下我的操作:
1.HSSFWorkbook 和SXSSFWorkbook区别
HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls,一张表最大支持65536行数据,256列,也就是说一个sheet页,最多导出6w多条数据
XSSFWorkbook:是操作Excel2007-2010的版本,扩展名是.xlsx对于不同版本的EXCEL文档要使用不同的工具类,如果使用错了,
会提示如下错误信息。
org.apache.poi.openxml4j.exceptions.InvalidOperationException
org.apache.poi.poifs.filesystem.OfficeXmlFileException
它的一张表最大支持1048576行,16384列,关于两者介绍,对下面导出百万数据很重要,不要使用错了!
2.使用SXSSFWorkbook对象,导出百万数据
SXSSFWorkbook使用方法和 HSSFWorkbook差不多,如果你之前和我一样用的HSSFWorkbook,现在想要修改,则只需要将HSSFWorkbook改成SXSSFWorkbook即可,下面有我介绍,具体使用也可参考API。
3.如何将百万数据分成多个sheet页,导出到excel
导出百万数据到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 {
response.reset();
// 获得国际化语言
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="
+ java.net.URLEncoder.encode(
DateUtil.getExportDate() + ".xlsx", "UTF-8"));//Excel 扩展名指定为xlsx SXSSFWorkbook对象只支持xlsx格式
OutputStream os = response.getOutputStream();
CellStyle style = workbook.createCellStyle();
// 设置样式
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 = requestContext.getMessage("employeeCode");
String employeeName = requestContext.getMessage("employeeName");
String orgName = requestContext.getMessage("orgName");
String startDate = requestContext.getMessage("start.date");
String endDate = requestContext.getMessage("end.date");
String courseCode = requestContext.getMessage("courseCode");
String courseName = requestContext.getMessage("courseName");
String sessionName = requestContext.getMessage("sessionName"); List<EmployeeTrainHistoryModel> list = null;
try {
//查询数据库中共有多少条数据
query.setTotalItem(employeeTrainHistoryService.fetchCountEmployeeTrainHistoryByQuery(query)); int page_size = 100000;// 定义每页数据数量
int list_count =query.getTotalItem();
//总数量除以每页显示条数等于页数
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);//设置第几页
list=employeeTrainHistoryService.getEmployeeTrainHistoryByQuery(query);
//新建sheet
Sheet sheet = null;
sheet = workbook.createSheet(System.currentTimeMillis()
+ CourseCompany+m);
// 创建属于上面Sheet的Row,参数0可以是0~65535之间的任何一个,
Row header = sheet.createRow(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 = header.createCell((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 history=list.get(i);
sheet.setDefaultColumnWidth((short) 17);
Row row = sheet.createRow(rowNum++);
row.createCell((short) 0).setCellValue(
history.getEmployeeCode());
row.createCell((short) 1).setCellValue(
history.getEmployeeName());
row.createCell((short) 2)
.setCellValue(history.getOrgName());
if (history.getTrainBeginTime() != null) {
row.createCell((short) 3).setCellValue(
DateUtil.toString(history.getTrainBeginTime()));
} else {
row.createCell((short) 3).setCellValue("");
}
if (history.getTrainEndTime() != null) {
row.createCell((short) 4).setCellValue(
DateUtil.toString(history.getTrainEndTime()));
} else {
row.createCell((short) 4).setCellValue("");
}
row.createCell((short) 5).setCellValue(
history.getCourseCode());
row.createCell((short) 6).setCellValue(
history.getCourseName());
row.createCell((short) 7).setCellValue(
history.getSessionName());
if (history.getHoursNumber() != null)
row.createCell((short) 8).setCellValue(
history.getHoursNumber().toString());
}
} 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数据,结果如图,不过还是感觉花费时间太多,不知道是不是我的程序写的有问题,知道的小伙伴,留个言吧!
java 分页导出百万级数据到excel的更多相关文章
- 使用POI导出百万级数据到excel的解决方案
1.HSSFWorkbook 和SXSSFWorkbook区别 HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls,一张表最大支持65536行数据,256列 ...
- 问问题_Java一次导出百万条数据生成excel(web操作)
需求:在web页面操作,一次导出百万条数据并生成excel 分析: 1.异步生成Excel,非实时,完成后使用某种方式通知用户 2.生成多个excel文件,并打包成zip文件,因为一个excel容纳不 ...
- php - 从数据库导出百万级数据(CSV文件)
将数据库连接信息.查询条件.标题信息替换为真实数据即可使用. <?php set_time_limit(0); ini_set('memory_limit', '128M'); $fileNam ...
- java 使用POI导出百万级数据
先看结果吧,这只是测试其中有很多因数影响了性能. 表总数为:7千多万,测试导出100万 表字段有17个字段 最终excel大小有60多兆 总耗时:126165毫秒 差不多2分多钟 其核心简单来说就是分 ...
- php 连接oracle 导出百万级数据
1,我们一般做导出的思路就是,根据我们想要的数据,全部查询出来,然后导出来,这个对数据量很大的时候会很慢,这里我提出来的思想就是分页和缓冲实现动态输出. 2.普通的我就不说了,下面我说一下分页和内存刷 ...
- JAVA使用POI如何导出百万级别数据(转)
https://blog.csdn.net/happyljw/article/details/52809244 用过POI的人都知道,在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会 ...
- JAVA使用POI如何导出百万级别数据
用过POI的人都知道,在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会常报OOM错误,这时候调整JVM的配置参数也不是一个好对策(注:jdk在32位系统中支持的内存不能超过2个G,而在6 ...
- JAVA使用POI如何导出百万级别数据(转载)
用过POI的人都知道,在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会常报OOM错误,这时候调整JVM的配置参数也不是一个好对策(注:jdk在32位系统中支持的内存不能超过2个G,而在6 ...
- MYSQL百万级数据,如何优化
MYSQL百万级数据,如何优化 首先,数据量大的时候,应尽量避免全表扫描,应考虑在 where 及 order by 涉及的列上建立索引,建索引可以大大加快数据的检索速度.但是,有些情况索引是 ...
随机推荐
- .net通用防SQL注入漏洞程序(Global.asax方式)
原理很简单:使用Global.asax中的Application_BeginRequest(object sender, EventArgs e)事件,实现表单或URL提交数据的获取,然后通过SQLI ...
- J2EE走向成功路-02-Struts2 配置(Maven)
在上一篇中,介绍了使用jar包搭建Struts2框架,这一篇中来介绍一下在Maven环境下搭建Struts2框架,主要为配置Maven. 1.下载Maven,官网:http://maven.apach ...
- Bash : test 命令
在 Bash 脚本中我们一般会使用 test 命令来进行条件检查.test 命令的返回值为 0 或 1.0 表示 true, 1 表示 false.简单起见,我们可以直接认为 test 的结果为 tr ...
- jquery各种事件使用方法总结(from:天宇之游)
ps:本博客转自博主 天宇之游 ,地址:http://www.cnblogs.com/cwp-bg/ ,再次感谢天宇之游.jquery事件使用方法总结 一.鼠标事件1. click():鼠标单击事 ...
- 使用Jquery.cookie.js操作cookie
query.cookie.js是一个基于jquery的插件,点击下载! 创建一个会话cookie: $.cookie(‘cookieName’,'cookieValue’); 注:当没有指明cooki ...
- python爬虫爬取代理IP
# #author:wuhao # #--*------------*-- #-****#爬取代理IP并保存到Excel----#爬取当日的代理IP并保存到Excel,目标网站xicidaili.co ...
- 面试题:使用LinkedList来模拟一个堆栈或者队列数据结构
请使用LinkedList来模拟一个堆栈或者队列数据结构. 堆栈:先进后出 First In Last Out (FILO) 队列:先进先出 First In First Out (FIFO) 我 ...
- UEFI启动视频详解:启动分析+N项操作实例
============================================================= ※※※※最给力的视频解说※※※※ 2011hiboy全部共享资料:立刻去 ...
- win10 uwp 俄罗斯方块
俄罗斯方块是一个很经典的游戏,做一个UWP俄罗斯方块没有什么用,我想说的是移植,把经典游戏移植到UWP. 我的所有博客都是抄别人的,这个才是我自己写的.后台很多代码还是抄别人的,我想说的是我们之前有很 ...
- java如何调用接口方式二
java如何调用接口 在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适,所以,问题来了,java如何调用接口?很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对 ...