以前我们数据库中存在大量的数据,我们要查询,怎么办?我们在没有经过设计的时候是这样来处理的,先写一个集合,然后执行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版权协议,转载请附上原文出处链接和本声明。