JAVA使用POI如何导出百万级别数据

  1. 在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会常报OOM错误, 这时候调整JVM的配置参数也不是一个好对策。
  2. POI3.8版本新出来了一个SXSSFWorkbook对象,它就是用来解决大数据量以及超大数据量的导入导出操作的,但是SXSSFWorkbook只支持.xlsx格式,不支持.xls格式的Excel文件。
  3. 基本都是使用的入门级web服务器tomcat,既然我们不推荐调整JVM的大小,那我们就要针对我们的代码来解决我们要解决的问题。
  4. 在POI3.8之后新增加了一个类,SXSSFWorkbook,采用当数据加工时不是类似前面版本的对象,它可以控制excel数据占用的内存,他通过控制在内存中的行数来实现资源管理,即当创建对象超过了设定的行数,它会自动刷新内存,将数据写入文件,这样导致打印时,占用的CPU,和内存很少。
  • 内存突发性占用,我们可以限制导出数据所占用的内存,这里我先建立一个list容器,list中开辟10000行的存储空间,每次存储10000行,用完了将内容清空,然后重复利用,这样就可以有效控制内存,所以我们的设计思路就基本形成了,所以分页数据导出共有以下3个步骤:
    1)求数据库中待导出数据的行数
    2)根据行数求数据提取次数
    3)按次数将数据写入文件

当业务数据超过200万300万了,直接打印数据到一个工作簿的一个工作表是实现不了的,数据必须打印到**多个工作表**,或者**多个工作簿**中代码实现如下:

public static void main(String[] args) throws Exception {
	Test3SXXFS tm = new Test3SXXFS();
	tm.jdbcex(true);
}
public void jdbcex(boolean isClose) throws InstantiationException, IllegalAccessException, 
			ClassNotFoundException, SQLException, IOException, InterruptedException {
		
	String xlsFile = "f:/poiSXXFSBigData.xlsx";		//输出文件
	//内存中只创建100个对象,写临时文件,当超过100条,就将内存中不用的对象释放。
	Workbook wb = new SXSSFWorkbook(100);			//关键语句
	Sheet sheet = null;		//工作表对象
	Row nRow = null;		//行对象
	Cell nCell = null;		//列对象
 
	//1. 使用jdbc链接数据库
	Class.forName("com.mysql.jdbc.Driver").newInstance();  
	String url = "jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8";
	String user = "root";
	String password = "123456";
	// 获取数据库连接
	Connection conn = DriverManager.getConnection(url, user,password);   
	Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);   
	String sql = "select * from hpa_normal_tissue limit 1000000";   //100万测试数据
	ResultSet rs = stmt.executeQuery(sql);  
	// 查询SQL后拿到数据
	ResultSetMetaData rsmd = rs.getMetaData();
	
	// 2. 开始时间
	long  startTime = System.currentTimeMillis();	
	System.out.println("strat execute time: " + startTime);
	int rowNo = 0;		//总行号
	int pageRowNo = 0;	//页行号
	// 3. 遍历所有数据
	while(rs.next()) {
		//打印300000条后切换到下个工作表,可根据需要自行拓展,2百万,3百万...数据一样操作,只要不超过1048576就可以
		if(rowNo%300000==0){
			System.out.println("Current Sheet:" + rowNo/300000);
			sheet = wb.createSheet("我的第"+(rowNo/300000)+"个工作簿");	//建立新的sheet对象
			sheet = wb.getSheetAt(rowNo/300000);						//动态指定当前的工作表
			pageRowNo = 0;												//每当新建了工作表就将当前工作表的行号重置为0
		}	
		rowNo++;
		nRow = sheet.createRow(pageRowNo++);	//新建行对象
		// 打印每行,每行有6列数据,rsmd.getColumnCount()==6,列属性的个数
		for(int j=0;j<rsmd.getColumnCount();j++){
			nCell = nRow.createCell(j);
			nCell.setCellValue(rs.getString(j+1));
		}
		if(rowNo%10000==0){
			System.out.println("row no: " + rowNo);
		}
		//Thread.sleep(1);	//休息一下,防止对CPU占用,其实影响不大
	}
	
	//4. 处理完成时间
	long finishedTime = System.currentTimeMillis();	
	System.out.println("finished execute  time: " + (finishedTime - startTime)/1000 + "m");
	// 5. 向文件中写数据
	FileOutputStream fOut = new FileOutputStream(xlsFile);
	wb.write(fOut);
	fOut.flush();		//刷新缓冲区
	fOut.close();
	// 6. 写文件时间
	long stopTime = System.currentTimeMillis();		
	System.out.println("write xlsx file time: " + (stopTime - startTime)/1000 + "m");
	if(isClose){
		this.close(rs, stmt, conn);
	}
}
	
//执行关闭流的操作
private void close(ResultSet rs, Statement stmt, Connection conn ) throws SQLException{
	rs.close();   
	stmt.close();   
	conn.close(); 
}

————————————————
版权声明:本文为CSDN博主「happyljw」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/happyljw/article/details/52809244

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值