ireport查询数据有80万条,tomcat7 内存溢出解决怎么解决

百万级数据量导出EXCEL解决方案分析 | 集深数据系统_报表系统
1. 问题概述 在web页面上显示的报表导出到excel文件里是一种很常见的需求, 润乾报表的类excel模型,支持excel文件数据无失真的导入导出, 然而,当数据量较大的情况下,就会遇到一些问题: 1. 2003Excel本身的支持最多65535行数据 2. 在这种大数据量的报表生成和导出中,要占用大量的内存,甚至内存溢出 难点:1.数据量大,报表在运算成ireport对象时每个sheet页内存不释放,可能内存溢出. 2.即使能够运算完ireport对象再导出Excel的过程中内存不释放,可能内存溢出.
2 . 案例 上海期货交易所 上海唯智信息
3. 解决方案 一. 对于数据超过了65535行的问题,很自然的就会想到将整个数据分块,利用excel的多sheet页的功能,将超出65535行后的数据写入到下一个sheet页中,即通过多sheet页的 方式,突破了最高65535行数据的限定, 具体做法就是,单独做一个链接,使用JSP导出,在JSP上通过程序判断报表行数,超过65535行后分SHEET写入。这样这个问题就得以解决了 二. 在这种大数据量的报表生成和导出中,要占用大量的内存,尤其是在使用TOMCAT的情况下,JVM最高只能支持到2G内存,则会发生内存溢出的情况。此时的内存开销 主要是两部分,一部分是该报表生成时的开销,另一部分是该报表生成后写入一个EXCEL时的开销。由于JVM的GC机制是不能强制回收的,因此,对于此种情形,我们要改变一种方式: 1. 将该报表设置起始行和结束行参数,在API生成报表的过程中,分步计算报表,比如一张20万行数据的报表,在生成过程中,可通过起始行和结束行分4-5次进行。这样,就 降低了报表生成时的内存占用,在后面报表生成的过程中,如果发现内存不够,即可自动启动JVM的GC机制,回收前面报表的缓存 2. 导出EXCEL的过程,放在每段生成报表之后立即进行,改多个SHEET页为多个EXCEL,即在分步生成报表的同时分步生成EXCEL,则通过 POI包生成EXCEL的内存消耗也得以降低。通过 多次生成,同样可以在后面EXCEL生成所需要的内存不足时,有效回收前面生成EXCEL时占用的内存 3. 再使用文件操作,对每个客户端的导出请求在服务器端根据SESSIONID和登陆时间生成唯一的临时目录,用来放置所生成的多个EXCEL,然后调用系统控制台,打包多个EXCEL为RAR 或者JAR方式,最终反馈给用户一个RAR包或者JAR包,响应客户请求后,再次调用控制台删除该临时目录。 4. 通过分段运算和生成,有效降低了报表从生成结果到生成EXCEL的内存开销。其次是通过使用压缩包,响应给用户的生成文件体积大大缩小,降低了多用户并 发访问时服务器下载文件的负担,有效减少多个用户导出下载时服务器端的流量,从而达到进一步减轻服务器负载的效果
4. 程序部分 1.JSP里导出的链接格式:&a href=“&%=request.getContextPath()%&/exportToExcel.jsp?report=分页标签.raq&path=reportFiles\&param=arg1=123,234;arg2=2″&导出Excel&/a& 也可用javascript的方式 2.导出EXCEL中对于取最大行数,可以在报表里多定义一个数据集专门取最大行数,在后台通过API方式解析,保证通用性避免代码中出现SQL,复杂SQL,存储过程等,如图:
jsp具体代码: &%@ page contentType=”text/charset=GBK“%& &%@ page import=”com.runqian.report4.model.*”%& &%@ page import=”com.runqian.report4.usermodel.*“%& &%@ page import=”com.runqian.report4.view.excel.*”%& &%@ page import=”com.runqian.report4.util.*”%& &%@ page import=”java.util.ArrayList“%& &%@ page import=”java.io.*”%& &%@ page import=”java.sql.*“/& &html& &head& &title&导出EXCEL&/title& &/head& &body& &% request.setCharacterEncoding(“GBK“); String root = getServletContext().getRealPath(“/”); String path = request.getParameter(“path“); //相对路径 String report = request.getParameter(“report“); //报表名 String param = request.getParameter(“param“); //报表参数 String filePath = root + path + ReportDefine rd2 = (ReportDefine) ReportUtils.read(filePath);//读取报表 Context context = new Context(); // 获得报表定义中的数据集集合 DataSetMetaData dsmd = rd2.getDataSetMetaData(); // 取到需要修改的数据集对象 //SQL检索类型:SQLDataSetConfig //复杂SQL类型:CSQLDataSetConfig //存储过程类型:ProcDataSetConfig SQLDataSetConfig dsc = (SQLDataSetConfig) dsmd.getDataSetConfig(0); String sql = dsc.getSQL(); //连接数据库,查询查询有多少条记录 Connection conn = context.getConnectionFactory(“zHouHuiHui“) .getConnection(); ResultSet rs = Statement stmt = conn.createStatement(); rs = stmt.executeQuery(sql); int num = 0; try { if (rs.next()) { num = rs.getInt(1); System.out.println(“条数:” + num); } } catch (SQLException e) { e.printStackTrace(); } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); } int rowCount = 65536;//每页最大行数 int pageCount = 0; if (num % rowCount == 0) { pageCount = num / rowC } else { pageCount = num / rowCount + 1; } System.out.println(“总共多少页 :” + pageCount); try { for (int k = 0; k & pageC k++) { //读取报表模板 context = new Context(); ReportDefine rd = (ReportDefine) ReportUtils.read(filePath); //运算报表 //创建要导出的excel报表 ExcelReport excel = new ExcelReport(); //计算前,设置参数 ParamMetaData pmd = rd.getParamMetaData(); if (param != null && param.trim().length() != 0 && pmd != null) { String[] para = param.split(“;”); String[] pa = String paramName = “”; //参数名 String paramValue = “null”; //参数值 for (int i = 0; i & para. i++) { out.println(para[i]); pa = para[i].split(“=”); paramName = pa[0]; if (pa.length == 1) { paramValue = “”; context.setParamValue(paramName, paramValue); } else { if (pa[1].indexOf(“,”) == -1) { paramValue = pa[1]; context .setParamValue(paramName, paramValue); } else { ArrayList objArrayList = new ArrayList(); String[] b = pa[1].split(“,”); for (int j = 0; j & b. j++) { objArrayList.add(b[j]); } context.setParamValue(paramName, objArrayList); } } } } context.setParamValue(“startRow“, 30000 * k); context.setParamValue(“endRow“, 30000 * (k + 1)); System.out.println(context.getParamValue(“startRow”)); System.out.println(context.getParamValue(“endRow”)); Engine enging = new Engine(rd, context); IReport iReport = enging.calc(); System.out.println(“[ToExcelServlet] – 运算报表结束!”); PrintSetup ps = iReport.getPrintSetup(); //取打印 ps.setPagerStyle(PrintSetup.PAGER_ROW); //设置报表分页方式为按数据行数分页 ps.setPaper((short) 0); //设置纸张类型 ps.setPaperWidth(1000); ps.setRowNumPerPage(65535); //设置按数据行数分页时每页的数据行数 iReport.setPrintSetup(ps); //设置打印配置*/ PageBuilder pb = new PageBuilder(iReport); //根据iReport中的PrintSetup里的信息进行分页 IReport[] ireports = pb.getAllPages(); //获得分页后的所有页集合 for (int i = 0; i & ireports. i++) { excel.export(ireports[i]); } excel.saveTo(“d://test//test” + k + “.xls”); } //将1个文件压缩成RAR格式 ExcelOutPut objRARFile = new ExcelOutPut(); int arg = objRARFile.RARFile(“d://test”, “d://test”, “”); OutputStream objOutputStream = response.getOutputStream(); response.setContentType(“application/octet-stream“); String httpHeader = “filename=report1.rar“; response.addHeader(“Content-Disposition”, httpHeader); FileInputStream infile = null;// 读取文件用 //生成对象用infile,准备读取文件 infile = new FileInputStream(“D://test.rar“); byte[] buffer = new byte[500]; int count = 0; count = infile.read(buffer); while (count & 0) { objOutputStream.write(buffer, 0, count); count = infile.read(buffer); } //ServletOutputStream sos = response.getOutputStream(); objOutputStream.close(); infile.close(); //以下两句必须要加,否则会报响应的输出流已经被占用 out.clear(); out = pageContext.pushBody(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } %& &/body& &/html& 3.将文件压缩成RAR格式,ExcelOutPut.java,具体代码: package com.runqian.report4. import java.io.BufferedR import java.io.IOE import java.io.InputStreamR public class ExcelOutPut { /* * * cmd 下调试成功的命令 * * 压缩:Rar a c:\test.rar c:\3Out_.MDB * * 解压:UnRar x * c:\test.rar d:\ * */ private static String rarCmd = “C://Program Files//WinRAR//Rar.exe a “; private static String unrarCmd = “C://Program Files//WinRAR//UnRar x “;
private static int count = 0; /** * * 将1个文件压缩成RAR格式 * * rarName 压缩后的压缩文件名(不包含后缀) * * fileName 需要压缩的文件名(必须包含路径) * * destDir 压缩后的压缩文件存放路径 * return 0 表示压缩完成 * * 1 表示由于一些原因失败 * * * @throws IOException * * @throws InterruptedException * */
public static int RARFile(String rarName, String fileName, String destDir) { rarCmd += destDir + rarName + “.rar ” + fileN String readStr = “”; try { System.out.println(“正在压缩文件…” + rarName + “.rar “); S Process p = Runtime.getRuntime().exec(rarCmd); BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(p.getInputStream())); while ((s = bufferedReader.readLine()) != null) System.out.println(s); try { p.waitFor(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(rarCmd); System.out.println(“finished rar the file: ” + fileName); } catch (IOException e) { e.printStackTrace(); return 1; } return 0; } public static void main(String[] args) { // TODO Auto-generated method stub // ExcelOutPut objRARFile = new ExcelOutPut(); // objRARFile.RARFile(“d://test”, “d://test”, “”); int count = 199999; // 记录数 count = count / 30000 + 1; System.out.println(count); } } 5. 总结 1. 该问题本身并不是润乾报表运算或者生成时有内存溢出BUG,而是WEB容器本身的问题和JVM本身的机制问题 2. 经过外部API改造,可以使用方法对问题进行规避 3. 该案例具有一定的通用性,完全可以做成一个独立的大报表导出的功能,将大数据量的报表分段运算成多个EXCEL,PDF或者WORD,通过外部程序进行压缩处理,响应给用户压缩包 4. 该需求本身合理性值得斟酌,但存在就是合理,也需要客户的配合,让步最终导致了该问题的解决记录(14)
iReport 是一款功能很强大的图标制作工具,但是网上教程、资料都比较少,基本上所有的属性设置都是英文的,上手比较困难,用了几天几乎全部靠自己摸索,现在记录下几个自己动手解决的问题。
设置某层的整体背景,可以通过放置组建面板中的静态文本,然后修改其背景颜色实现,我没有找到直接设置背景的属性。有时候预览的时候会报错,描述为“内存溢出”,然后软件卡死,系统进程中的java.exe占CPU的80%以上。这种情况可能并不是内存溢出的问题,只是某个组件放置位置、尺寸错误导致的。检查所有的组件,确保每个都是绿色边框或者深蓝边框。组件不能互相遮挡。组件成功放置的标志是组建的边框变成深蓝色,例如这样:。其他的颜色,例如红色边框、黄色边框,代表目前不可用,还需要调整;绿色的边框代表可以在iReport中预览,但是放在web项目中的时候此组件并不能显示。使用柱状图时,如果X轴节点过多,就会导致节点描述互相遮挡,变成这样:有两种办法可以解决:1.
把字体变小,把节点描述文字倾斜,chart的属性设置如下,最后实现效果是这样:;2.
使用横向的图标样式,效果如下:,但这种方式能只解决了横向遮挡问题,如果数据太多而且高度不够时,Y轴方向上会出现重影现象。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:7827次
排名:千里之外
原创:23篇
(1)(3)(2)(1)(1)(1)(4)(1)(4)(1)(4)(1)51cto_blog 的BLOG
用户名:51cto_blog
文章数:294
评论数:8193
访问量:1499838
注册日期:
阅读量:5863
阅读量:12276
阅读量:420155
阅读量:1108451
51CTO推荐博文
Java是Sun公司推出的一种编程语言,也是一种跨平台的程序设计语言,在编程语言排行榜中也居于三甲位置。本文档收集的资料有Java面试题,教程,编程技巧等,供大家方便统一阅读。&
1 Java程序员面试题集锦&推荐&&&
2 疯狂Java&讲义&李刚&推荐&
3 Java多线程初学者指南&推荐&
4 Java线程系列实用教程&
5&零基础学&JAVA&之&Java SE&
6&算法导论Java实现之排序&
7 Java设计模式圣经连载&推荐&
8&深入研究&Java.lang&的类&
9 Java&程序员,上班那点事&
10 JAVA&游戏编程&
1 Java多线程编程总结&推荐&
2&【门诊集锦】快速驾驭轻量级Java EE企业应用开发&推荐
3 Java线程:线程的调度-休眠&
4 Java线程:大总结&推荐&
5 Java网络编程从入门到精通(11):使用NetworkInterface类获得网络接口信息
6 Java字符集编码与转码&
7 Java网络编程从入门到精通(30):定制accept方法
8&防止同一个Java应用重复启动的shell脚本
9 Java的动态代理&
10 Java线程:线程私有变量&
11 Java相对路径读取文件&
12 Java根据图片建立不规则窗体详解
13 Java回归线之Static修饰符&
14 Java字符编码根本原理
15&通过游戏学习java面向对象编程(1)
16 Java处理带BOM的文本&
17&关于Java开发环境的配置问题
18 Java环境变量配置问题&
19&浅谈java之xml解析&
20 Java抽象类和接口的学习&
21 Java中的BoneCP数据库连接池用法
22 JAVA程序内存溢出问题的分析
23 JAVA游戏编程之三----j2me&手机游戏入门开发--俄罗斯方块_4_增加消除行声音
24&利用Java正则表达式去掉SQL代码中回车换行和多余空格
25 Java开源报表JasperReport、iReport4.5.1使用详解(三)
26 Java关键字final、static使用总结
27 Java关键字this、super使用总结
28 Java异常处理总结&
29 Java程序员必看--扩展鼠标右键菜单功能
30 Java:谈谈protected访问权限
31 Java关键字介绍之static&
32 Java:初始化类、变量、程序块加载探讨
33 Java集合框架使用总结&&
34 Java虚拟机(JVM)参数配置说明
35 Java:数据类型转换&
36 Java链接oracle数据库&
37 Java学习杂谈&
38 Java:在Bean中使用PropertyChangeSupport支持PropertyChangeListeners
39 Java&泛型的理解与等价实现&
40 Java&反射机制深入研究&
41 Java克隆(Clone)的应用&
42 Java运行时绑定探讨&
43 Java日期格式化及其使用例子收集
44 Java中的main()方法详解&
45 Java:对象的强、软、弱和虚引用
46&通过Java反射调用方法&
47 Java读取properties文件的思考&
48 Java对代码表的处理技巧&
49&深入探索Java对象的序列化&
50&探讨Java内部类的可见性&
51 Java操作DB2 XML数据实践&
52 Java:应用Observer接口实践Observer模式
53 Java:集合类性能分析&
54 Java实现的Sequence工具&
55 Java:设计与使用迭代器&
56 Java:使用synchronized和Lock对象获取对象锁
57 Java:定时启动线程&
58&深入Java字符串&
59 Java与模式:合成模式&
60 Java与模式:适配器模式&
61 Java与模式:装饰(Decorator)模式
62 Java实现FTP上传下载功能&
63 JAVA面试题解惑系列(一)&&类的初始化顺序
64 Java通过XML Schema校验XML&
65 Java线程:线程状态的转换&
66 Java中对象的串行化&
67 JDK工具&javac命令详解&
68 JAVA学习笔记--关于System.out.println()
69 Java实现动画逐字打印&
70 [零基础学JAVA]Java SE面向对象部分-11.面向对象基础(06)
71 Java&生成静态html的一段代码&
72&【小项目】用Java写一个日历小程序-思路
73&改写的日历小程序(Java)&
74 [零基础学JAVA]Java SE面向对象部分-17.面向对象高级(05)
75 Java版AVG游戏开发入门[0]&&游戏模式转换中的事件交互
76 [零基础学JAVA]Java SE应用部分-23.多线程(01)
77 Java中的DatagramPacket与DatagramSocket的初步
78 Java版战棋(SLG)游戏AI及寻径处理入门
79 Java内存分析&
80 Java操作Microsoft Word之jacob
81 [零基础学JAVA]Java SE应用部分-32.Java网络编程
82 Java实现文件的上传&
83 Java游戏开发中怎样才能获得更快的FPS?
84 Java程序员,笔试必读&
85 Java&编程思想笔记之this关键字(包括一些对方法在内存中的分配的解析)
86 Java EE WEB工程师培训-JDBC+Servlet+JSP整合开发之33.HTML表单
87 Java程序员,面试必读&
88 Java的FTP协议级客户端实现详解
89 Java2.5D游戏的设计与实现(3)&八方走法实现原理及相关代码
90 Java游戏中延迟下载资源及调用示例
91 Java字符串与文件的互转&
92 Java&集合框架(Collection)和数组的排序
93 Java中2.5D游戏(斜45度角)的设计与实现(2)
94&如何应用Java的静态内部类&
95&如何应用Java的可变参数&
96&浅谈Java集合中Array(数组)的应用
97 Java模拟HTTP的Get和Post请求&
98 Java获取图片的宽高等信息&
99&细说Java的API类JOptionPane&
100 Java模拟HTTP的Get和Post请求(增强)
101&如何编写和应用Java的自定义异常类
102 Java中的&goto&实现&
103&超微型Java数据库连接池&
104 JAVA-Astar算法实现&
105&深入Java单例模式&
106 Java中ArrayList和LinkedList的比较
107 JAVA AJAX教程第三章&AJAX详细讲解
108&观察者模式-Java自定义事件&
109 Java中取得当月最后一天的四种方法
110 Java各种中文乱码问题的解决(1)get和post请求
了这篇文章
类别:┆阅读(0)┆评论(0)
13:10:46 23:29:13 10:27:19

我要回帖

更多关于 tomcat7 内存溢出解决 的文章

 

随机推荐