18

巨大なテーブルをカスタムXMLファイルに変換するタスクが与えられました。この仕事にはJavaを使用します。

単に「SELECT*FROM customer」を発行すると、大量のデータが返され、最終的にOOMが発生する可能性があります。レコードが利用可能になったらすぐに処理し、その後SQL取得プロセス中にメモリからレコードを削除する方法はありますか?

---2009年7月13日に編集

私の質問を詳しく説明させてください。1つのdbサーバーと1つのアプリケーションサーバーがあります。アプリケーションでselectクエリを発行すると、データはデータベースサーバーからアプリサーバーに移動します。

ResultSetは、クエリ内のすべてのレコードを受信するまで待機する必要があると思います(間違っている場合は修正してください)。フェッチサイズを4に設定しても、1000レコードのテーブルの場合、アプリサーバーのヒープメモリに1000レコードが残ってしまいますが、正しいですか?フェッチサイズは、dbサーバーとの間のラウンドトリップの数にのみ影響します。

私の質問は、アプリサーバーに到着した直後にその4つ(または任意の数)のレコードの処理を開始し、アプリサーバーのメモリを解放するためにそれを破棄する方法です。

4

6 に答える 6

6

もう少し情報があれば、もっと役立つ答えを得ることができます。

MySQLを使用している場合:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
       java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

http://www.oracle.com/technology/tech/java/sqlj_jdbc/htdocs/jdbc_faq.htmlから:

java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);
于 2009-07-10T04:49:56.830 に答える
4

これと同じ解決策を使用できると思います。スクロール可能な結果セット。

于 2009-07-10T04:51:33.097 に答える
4

JDBCを使用している場合は、一度に1つのレコードを反復処理するカーソルでResultSetを使用できます。次に、DOMを使用してXMLを構築するのではなく、XMLを一度に1レコードずつファイルに書き出すようにする必要があります。

于 2009-07-10T04:52:02.037 に答える
4

私の経験から学んだ経験則の1つは、データベースからアプリケーションサーバーにすべてのデータを持ち込むことは絶対にしないということです。実行できることの1つは、データをページングする手順を実装することです。

約1000〜5000レコードを含む1ページのデータを取得して処理し、次のページのデータを再度フェッチできます。

于 2009-07-10T04:52:30.910 に答える
1

テーブル全体をエクスポートするための概念。(専門家への注意:私はその欠点を認識しています。)

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class FullTableExport {
    public static String toXML(String s) {
        if (s != null) {
            StringBuilder b = new StringBuilder(s.length());
            for (int i = 0, count = s.length(); i < count; i++) {
                char c = s.charAt(i);
                switch (c) {
                case '<':
                    b.append("&lt;");
                    break;
                case '>':
                    b.append("&gt;");
                    break;
                case '\'':
                    b.append("&#39;");
                    break;
                case '"':
                    b.append("&quot;");
                    break;
                case '&':
                    b.append("&amp;");
                    break;
                default:
                    b.append(c);
                }
            }
            return b.toString();
        }
        return "";
    }
    public static void main(String[] args) throws Exception {
        String table = "CUSTOMER";
        int batch = 100;

        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection(
            "jdbc:oracle:thin:@server:orcl", "user", "pass");
        PreparedStatement pstmt = conn.prepareStatement(
            "SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
        ResultSet rs = pstmt.executeQuery();
        rs.setFetchSize(batch);
        ResultSetMetaData rsm = rs.getMetaData();
        File output = new File("result.xml");
        PrintWriter out = new PrintWriter(new BufferedWriter(
            new OutputStreamWriter(
            new FileOutputStream(output), "UTF-8")), false);
        out.printf("<?xml version='1.0' encoding='UTF-8'?>%n");
        out.printf("<table name='%s'>%n", toXML(table));
        int j = 1;
        while (rs.next()) {
            out.printf("\t<row id='%d'>%n", j++);
            for (int i = 1; i <= rsm.getColumnCount(); i++) {
                out.printf("\t\t<col name='%s'>%s</col>%n", 
                    toXML(rsm.getColumnName(i)), 
                    toXML(rs.getString(i)));
            }
            out.printf("\t</row>%n");
        }
        out.printf("</table>%n", table);
        out.flush();
    }
}

欠点を編集します(@JSに感謝します):

  • ojdbc以外で使用される外部ライブラリはありません
  • 何も閉じられていません
  • 一般的な例外がスローされます
  • 主な方法です
  • XML生成のための印刷の使用
  • Oracle固有のSQL
  • プレーンテキストのパスワード
  • 一部の列は文字列表現で扱いにくいように見えます
  • UTF-8は国際的すぎます
  • XML構造のフットプリントが大きい
于 2009-07-10T08:14:24.403 に答える
0

OOMエラーが発生しているのはどの段階ですか?データの取得またはXMLファイルへのデータの処理ですか?

データを取得する場合は、データをバッチで取得します。最初に行の総数を取得し、主キーで選択を並べ替え、選択した行をチュアブルサイズに制限します。

XMLファイルの作成時に、各顧客のXMLノードをSystem.out.printlnに送信し、メモリに保持しないでください。コンマ行を介してプログラムを起動し、すべての出力をファイルにリダイレクトします。

java MyConverter > results.txt

レコードをループすると、すべてがファイルに保存されます。

于 2009-07-10T06:18:41.113 に答える