由于项目需要,从MYSQL中导出元数据,形成XML文档。数据记录数在两W左右,大小差不多有三十MB以上。我现在采用的是JDOM或者DOM4J都报了内存溢出错误。请问有没有什么其他的方式能够解决这问题呢?

解决方案 »

  1.   

    package ctais.business.jczc.yhs.wfwzxxcx;import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;import javax.xml.parsers.SAXParser;
    import javax.xml.parsers.SAXParserFactory;
    import java.io.Serializable;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;/**
     * Title: SAX 方式解析 XML 文件
     * Description:解决大文件报OutOfMemory的问题
     * Company: ****
     * @author: Pagecn
     * @date: YYYY-MM-DD
     */
    public class SAXApp extends DefaultHandler implements Serializable {
        private String LableName = "";  // 节点名称
        private String LableValue = ""; // 节点值
        private HashMap hm = new HashMap();     // 临时保存数据
        private List list = new ArrayList();    // 保存插入的SQL语句
        /**
         * 根据文件路径建立 SAX解析器
         * @param uri
         */
        public void parseURI(String uri) {
            try {
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp = spf.newSAXParser();
                sp.parse(uri, this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }    /**
         * 开始遍历
         * @throws SAXException
         */
        public void startDocument() throws SAXException {
            //System.out.println("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
        }    /**
         * 取开始节点名称
         * @param namespaceURI
         * @param localName
         * @param rawName
         * @param attrs
         * @throws SAXException
         */
        public void startElement(String namespaceURI, String localName, String rawName, Attributes attrs) throws SAXException {
            LableName = rawName;
        }    /**
         * 取节点值
         * @param ch
         * @param start
         * @param length
         * @throws SAXException
         */
        public void characters(char ch[], int start, int length) throws SAXException {        // 过滤回车LableValue.indexOf("\n") == -1
            if (LableValue.indexOf("\n") != -1) {
                LableValue = "";
            }
            // 处理节点值过长,出现分段读取的情况
            if (LableName.equals("COL1") || LableName.equals("COL2") || LableName.equals("COL3")) {
                LableValue += new String(ch, start, length);
                LableValue.trim();
            } else {
                LableValue = new String(ch, start, length);
            }
        }    /**
         * 取结束节点名称
         * @param namespaceURI
         * @param localName
         * @param rawName
         * @throws SAXException
         */
        public void endElement(String namespaceURI, String localName, String rawName) throws SAXException {
            try {
                // 获得有用节点信息放入HashMap
                if (!(rawName.equals("XX") || rawName.equals("ITEM"))) {
                    hm.put(rawName, LableValue.trim());
                    LableValue = "";
                }
                // 组装SQL
                if (rawName.equals("ITEM")) {
                    list.add("INSERT INTO TAB_NAME (COL1,COL2,COL3)"
                            + " VALUES("
                            + "'" + hm.get("COL1") + "',"
                            + "'" + hm.get("COL2") + "',"
                            + "'" + hm.get("COL3") + "')");
                    hm.clear();
                }
            } catch (Exception e) {
                e.getMessage();
            }    }    /**
         * 遍历结束
         * @throws SAXException
         */
        public void endDocument() throws SAXException {
            Statement stmt = null;
            Connection conn = null;
            int initsize = 0;
            int size = 100;
            try {
                // 获取数据库连接
                Class.forName("oracle.jdbc.driver.OracleDriver");
                conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:SID", "USER", "PASSWORD");
                stmt = conn.createStatement();
                initsize = stmt.getFetchSize();
                stmt.setFetchSize(size);            // 批量插入数据,提高存储效率
                for (int i = 0; i < list.size(); i++) {
                    stmt.addBatch((String) list.get(i));
                }
                stmt.executeBatch();            // 关闭数据库句柄
                stmt.setFetchSize(initsize);
                stmt.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
                try {
                    if (stmt != null) {
                        if (initsize != 0) {
                            stmt.setFetchSize(initsize);
                        }
                        stmt.close();
                    }
                    if (conn != null) {
                        conn.close();
                    }
                } catch (SQLException ee) {
                    ee.printStackTrace();
                }
            }
        }    /**
         * 测试方法
         * 处理过>100M的XML文件,顺利完成,不过这种方式比较适合格式比较整齐、单一的XML文件
         */
        public static void main(String args[]) {
    /*
    <ROOT>
            <XX>
            <ITEM>
              <COL1/>
              <COL2/>
              <COL3/>
                </ITEM>
            </XX>
        </ROOT>
    */
            SAXApp st = new SAXApp();
            st.parseURI("C:\\test.xml");
            st.parseURI("C:\\ykk2007.xml");
        }
    }
      

  2.   

    如果搂主是准备将导出的数据导入到ORACLE,而且在导出时采用CSV或者TXT的格式而不是XML,就可以使用sqlldr这个命令。
    此命令相当的快,100W行小于120秒,同时可以过滤一些不规范的数据到bad.txt,不过需要写个控制文件,也就是***.ctl,很简单,可以搜一下
    sqlldr user/password@SID control=***.ctl log=**_log.log bad = bad.txt