JAVA使用POI如何导出百万级别数据,防止内存溢出

      以前我们数据库中存在大量的数据,我们要查询,怎么办?我们在没有经过设计的时候是这样来处理的,先写一个集合,然后执行jdbc,将返回的结果赋值给list,然后再返回到页面上,但是当数据量大的时候,就会出现数据无法返回,内存溢出的情况,于是我们在有限的时间和空间下,通过分页将数据一页一页的显示出来,这样可以避免了大数据量数据对内存的占用,也提高了用户的体验,在我们要导出的百万数据也是一个道理,内存突发性占用,我们可以限制导出数据所占用的内存,这里我先建立一个list容器,list中开辟10000行的存储空间,每次存储10000行,用完了将内容清空,然后重复利用,这样就可以有效控制内存,所以我们的设计思路就基本形成了,所以分页数据导出共有以下3个步骤:

1、求数据库中待导出数据的行数

2、根据行数求数据提取次数

3、按次数将数据写入文件

  注:当数据量超过百万必须拆分到多个工作表,或者多个工作簿中才能实现。因为一个sheet最多行数为1048576。

附上代码(工作中实例)

     

	@RequestMapping("/exportmq")
	public String exportmq(HttpServletResponse response, HttpServletRequest req) throws Exception {
		long startTime = System.currentTimeMillis();
		logger.info("激活码导出开始:" + TimeUtil.getDateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));
		setResponseHeader(response, "card.xlsx");
		List<Map<String, Object>> list1 = new ArrayList<>();
		JdbcTemplate template = JdbcTemplateManager.getTemplate();
		String log_id = req.getParameter("log_id");
		String card_code = req.getParameter("card_code");
		String role_id = req.getParameter("role_id");
		String server_id = req.getParameter("server_id");
		String user_name = req.getParameter("user_name");
		int i = 0;
		// 最重要的就是使用SXSSFWorkbook,表示流的方式进行操作
		// 在内存中保持100行,超过100行将被刷新到磁盘
		SXSSFWorkbook wb = new SXSSFWorkbook(100);
		Row row = null;
		Sheet sh = null;

		try {
			String sql1 = "select count(1) sums from m_game_card where 1 = 1 ";
			if (StringUtils.isNotBlank(log_id)) {
				sql1 += " and log_id = " + log_id;
			}
			if (StringUtils.isNotBlank(card_code)) {
				sql1 += " and card_code = '" + card_code + "'";
			}
			if (StringUtils.isNotBlank(role_id)) {
				sql1 += " and role_id = " + role_id;
			}
			if (StringUtils.isNotBlank(user_name)) {
				sql1 += " and server_id = " + server_id;
			}
			if (StringUtils.isNotBlank(server_id)) {
				sql1 += " and user_name = '" + user_name + "'";
			}
			List<Map<String, Object>> list = template.queryForList(sql1);
			int sum = Integer.valueOf(list.get(0).get("sums").toString());
			int page_size = 10000;
			int page_maxsize = 500000;
			int timesss = (int) Math.ceil(sum / 500000.0);
			int rowNo = 0; // 总行号
			int pageRowNo = 0; // 页行号

			for (int s = 0; s < timesss; s++) {
				if (rowNo % 500001 == 0) {
					sh = wb.createSheet();// 建立新的sheet对象
					wb.setSheetName(s, "第" + (s + 1) + "个sheet");// 动态指定当前的工作表
					pageRowNo = 0; // 每当新建了工作表就将当前工作表的行号重置为0
				}
				// -----------定义表头-----------
				row = sh.createRow(pageRowNo++); // 创建第一行对象
				rowNo++;
				Cell cel0 = row.createCell(0);
				cel0.setCellValue("卡号");
				Cell cel2 = row.createCell(1);
				cel2.setCellValue("卡类型");
				Cell cel3 = row.createCell(2);
				cel3.setCellValue("用户名");
				Cell cel4 = row.createCell(3);
				cel4.setCellValue("状态");
				Cell cel5 = row.createCell(4);
				cel5.setCellValue("玩家角色");
				Cell cel6 = row.createCell(5);
				cel6.setCellValue("玩家所在区服");
				if ((page_maxsize) * (s + 1) > sum) {
					page_maxsize = sum - s * page_maxsize;
				}
				int times = page_maxsize % page_size > 0 ? (page_maxsize / page_size + 1) : (page_maxsize / page_size);
				for (i = 0; i < times; i++) {
					int page = rowNo - (s + 1);
					StringBuffer sql2 = new StringBuffer();
					sql2.append(
							"select card_code,  expiration_type, user_name , status ,roleid, server_id from m_game_card where 1=1 ");

					if (StringUtils.isNotBlank(log_id)) {
						sql2.append(" and log_id = " + log_id);
					}
					if (StringUtils.isNotBlank(card_code)) {
						sql2.append(" and card_code = '" + card_code + "'");
					}
					if (StringUtils.isNotBlank(role_id)) {
						sql2.append(" and role_id = " + role_id);
					}
					if (StringUtils.isNotBlank(user_name)) {
						sql2.append(" and server_id = " + server_id);
					}
					if (StringUtils.isNotBlank(server_id)) {
						sql2.append(" and user_name = '" + user_name + "'");
					}

					sql2.append(" order by status desc  limit " + page + " ," + page_size);

					list1 = template.queryForList(sql2.toString());
					int len = page_size;
					if (list1.size() < page_size) {
						len = list1.size();
					}
					for (int j = 0; j < len; j++) {
						rowNo++;
						row = sh.createRow(pageRowNo++);
						Cell cel0_value = row.createCell(0);
						cel0_value.setCellValue(
								list1.get(j).get("card_code") == null ? "" : list1.get(j).get("card_code").toString());
						Cell cel1_value = row.createCell(1);
						Object type  = list1.get(j).get("expiration_type");
						String types = "";
						if("".equals(type) || null == type){
							type = "";
						}else{
							if("0".equals(type.toString())){
								types = "永久卡";
							}else if("1".equals(type.toString())){
								types = "时效卡";
							}
						}
						cel1_value.setCellValue(types);
						Cell cel2_value = row.createCell(2);
						cel2_value.setCellValue(
								list1.get(j).get("user_name") == null ? "" : list1.get(j).get("user_name").toString());
						Cell cel3_value = row.createCell(3);
						Object status = list1.get(j).get("status");
						String statustr = "";
						if("".equals(status) || null == status){
							statustr = "";
						}else{
							if("0".equals(status.toString())){
								statustr = "未使用";
							}else if("1".equals(status.toString())){
								statustr = "已使用";
							}else{
								statustr = "无效卡";
							}
						}
						cel3_value.setCellValue(statustr);
						Cell cel4_value = row.createCell(4);
						cel4_value.setCellValue(
								list1.get(j).get("roleid") == null ? "" : list1.get(j).get("roleid").toString());
						Cell cel5_value = row.createCell(5);
						cel5_value.setCellValue(
								list1.get(j).get("server_id") == null ? "" : list1.get(j).get("server_id").toString());
					}
					list1.clear();
				}

			}
			// FileOutputStream fileOut = new
			// FileOutputStream("C:\\Users\\man\\Desktop");
			OutputStream fileOut = response.getOutputStream();
			wb.write(fileOut);
			fileOut.close();
			wb.dispose();

		} catch (Exception e) {
			e.printStackTrace();
		}
		long offTime = System.currentTimeMillis();
		logger.info("导出激活码用时:" + (offTime - startTime) + "ms");
		return null;
	}

 

 

/**
	 * 设置响应头
	 */
	public void setResponseHeader(HttpServletResponse response, String filename) {
		try {
			response.setContentType("application/msexcel;charset=UTF-8");
			response.setHeader("Content-Disposition",
					"attachment;filename=" + new String(filename.getBytes("gb2312"), "iso8859-1"));
			// 客户端不缓存
			response.addHeader("Pargam", "no-cache");
			response.addHeader("Cache-Control", "no-cache");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

 

   到这里就成功了,一定要明白这个过程,领会这种思想!

 

 


版权声明:本文为kobe_2014_ming原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。