2011-07-01 51 views
10

私の目標は、実際にはデータベースのすべてのデータをXMLファイルにダンプすることです。データベースはそれほど大きくはない、それは約300MBだ。問題は、256MBのメモリ制限(JVM内)のみです。だから明らかに私はすべてをメモリに読み込むことはできません。MyBatisで非常に大量のデータを扱う

私はこの問題を、getList(... int skip, int max)と呼んで、iBatis(iBatisではmyBatisではありません)を複数回使用して解決しました。増分はskipです。それは私の記憶上の問題を解決しますが、私は速度に感心しません。変数名は、フードの中でメソッドが何をするかは、result-setスキップしてから指定されたレコード全体を読み取ることを示しています。これは私にとってかなり冗長に思えます(私はそれがメソッドがやっていることではありません、私は変数名の基底を推測しています)。

私のアプリケーションの次のバージョンでmyBatis 3に切り替えました。私の質問は、myBatisで大量のデータチャンクをチャンクで処理する方法はありますか?とにかくmyBatisを最初のN個のレコードに処理し、結果セットの接続を開いたままで呼び出し元に戻します。次回ユーザーがgetList(...)を呼び出すと、何もせずにN + 1レコードからの読み取りを開始します「スキップする」?

答えて

7

いいえ、mybatisには、結果をストリームするフル機能がありませんまだです。

EDIT 1: ネストされた結果マッピングが必要ない場合は、カスタム結果ハンドラを実装して結果をストリーミングできます。 MyBatisの現在のリリースバージョンで。 (3.1.1)現在の制限は、複雑な結果マッピングを行う必要がある場合です。 NestedResultSetHandlerはカスタム結果ハンドラを許可しません。修正が利用可能で、現在3.2の対象となっているようです。 Issue 577を参照してください。

要約すると、MyBatisを使用して大きな結果セットをストリーミングするには、必要になります。

  1. Implement your own ResultSetHandler
  2. フェッチサイズを大きくします。 (Guillaume Perrotによって以下に記載されているように)
  3. ネストされた結果マップについては、Issue 577で説明した修正を使用してください。また、この修正により、大きな結果セットでメモリの問題が解決されます。
16

myBatis CANストリームの結果。必要なのはカスタム結果ハンドラです。これにより、各行を個別に取得してXMLファイルに書き込むことができます。 resultHandlerがResultHandlerインタフェースを実装するクラスのインスタンスである

session.select(
    "mappedStatementThatFindsYourObjects", 
    parametersForStatement, 
    resultHandler); 

:全体的なスキームは次のようになります。このインタフェースはただ1つのメソッドhandleResultを持っています。このメソッドは、ResultContextオブジェクトを提供します。このコンテキストから、現在読み込まれている行を取得し、それを使って何かを行うことができます。

handleResult(ResultContext context) { 
    Object result = context.getResultObject(); 
    doSomething(result); 
} 
+8

あなたの答えは重要ではありません。@Options(fetchSize = Integer.MIN_VALUE)(またはXMLに相当するもの)をステートメントに追加する必要があります。 MyBatis 3.0.5では動作しませんでした(Eclipse Memory Analyzerで調べました)。 MyBatis 3.1.1にアップグレードしたところ、ストリーミングは正常に動作しました。 –

2

handleResultは、クエリが取得するレコード数だけ受信します。ポーズはありません。

処理するレコードが多すぎる場合は、sqlSessionFactory.getSession()。getConnection()を使用しました。 通常のJDBCと同様に、Statementを取得し、Resultsetを取得し、レコードを1つずつ処理します。セッションを閉じることを忘れないでください。

0

すべてのデータをテーブルから並べ替える必要がない場合は、SQLでページ番号を直接指定しないでください。テーブル全体をチャンクに分割するために、オフセットとして異なるレコードidを指定するquery文に制限を設定します。各行は、行の制限が妥当な数であればメモリに直接読み込むことができます。

SQLのようなものが考えられます。

SELECT * FROM resource 
    WHERE "ID" >= continuation_id LIMIT 300; 

私は、これはMyBatisの中に異なる機能の問題を取り除く、または任意の取得、チャンクですべてのデータをダンプするためにあなたのための代替ソリューションとして見ることができると思いますパーシスタンス層、サポート。

関連する問題