由于客户的需要,WEB应用程序中有一项功能是要将数据库中的一张表导出成XML文件下载。最初采用的方案是一次将表中的所有数据读出,然后在内存中通过DOM完整地组织XML文档,完成以后通过转换将其输出到页面的响应流中。在数据量小时,这样的方案没有什么问题,但是当数据库中的数据比较多时,程序运行就产生了异常,查看Tomcat的日志,发现是内存溢出了。如何解决这个问题呢?
要从根本上解决这个问题,就要想办法降低内存的占用。显然这个方案中有两处占用了大量内存,一是将表中的数据全部读出保存于内存之中;二是在内存中将XML组织完整以后才向客户端输出。第一点很容易解决,采取每次读取一批数据分多次读取即可解决,而第二点,可以通过Java的stax解决。
以下是一段实现将大量数据形成XML文件并发送到客户端浏览器下载的例程,为了简明起见,数据是直接通过代码生成的而不是从数据库中读取的。该代码生成的XML约1G大小,经测试,未再发生内存溢出的错误。
package net.yanzhijun.edu;
import java.io.IOException;
import java.io.OutputStreamWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
/**
* Servlet implementation class ExportXml
*/
public class ExportXml extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public ExportXml() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
sample(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
sample(request, response);
}
private void sample(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType(“application/octet-stream”);
response.setHeader(“Content-Disposition”, “attachment; filename=\”sample.xml\”;”);
response.setHeader(“Content-Transfer-Encoding”,”binary”);
response.setHeader(“Cache-Control”, “must-revalidate, post-check=0, pre-check=0″);
response.setHeader(“Pragma”, “public”);
try
{
XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();
OutputStreamWriter output = new OutputStreamWriter(response.getOutputStream(), “UTF-8″);
XMLStreamWriter xml=outputFactory.createXMLStreamWriter(output);
xml.writeStartDocument(“UTF-8″, “1.0″);
// 根结点
xml.writeStartElement(“root”);
for(int i = 1; i < 10000000; i++)
{
//子结点开始
xml.writeStartElement(“list”);
xml.writeAttribute(“id”, “ID” + i);
xml.writeAttribute(“attr1″, “ATTR1_” + i);
xml.writeAttribute(“attr2″, “ATTR2_” + i);
xml.writeAttribute(“attr3″, “ATTR3_” + i);
xml.writeAttribute(“attr4″, “ATTR4_” + i);
// 子结点结束
xml.writeEndElement();
}
// 根结点结束
xml.writeEndElement();
xml.flush();
xml.close();
}
catch(IOException e)
{
e.printStackTrace();
}
catch( XMLStreamException e)
{
e.printStackTrace();
}
}
}
欢迎访问梦断酒醒的博客http://www.yanzhijun.net