iterableをチャンクする

私は Iterable を返すデータベースからオブジェクトのロードを取得するメソッドを持っています。

今のところ、私はデータベースから結果セットをロードし、そこからオブジェクトを構築し、それらのオブジェクトをコレクションに追加しています。

明らかに、私は、このメソッドを使用してロードできるデータの量と、Bad Things Happenを使い果たした場合には、メモリが制限されています。

実装を変更して、一度にすべてを取得するのではなく、データベースからデータをチャンクし、その結果のオブジェクトを Iterable インタフェースを介してクライアントに公開します。私のデータベースドライバはちょっとしたことができるので、私の最初の考えはこれを行う Iterable のカスタム実装です。

これは良いアプローチですか?ランタイムやライブラリで既にサポートされている可能性のあるものとして私を襲ってきます.ORMソリューションは関係ありません。

2
Iterator だけでなく、 Iterable を実装したい理由がありますか?反復を再開する機能を追加する必要がないので、後の方が簡単でしょう。
追加された 著者 Joachim Sauer,
良い点 - 全く理由なし
追加された 著者 brabster,

2 答え

個人的に私が考えることができる最も簡単な解決策は ResultSet のシンラッパーとして Iterator を実装することです。それにはいくつかの利点があります。

  • 再現可能なSQL文を提供する必要はありません(たとえば、ソートされていない結果をストリームすることができます)。
  • に頼る必要はありません反復可能な読み込みは、コストがかかる可能性があります。
  • JDBCドライバがうまくいけば、そのストリーミング結果機能を使用することができます(警告:一部のJDBCドライバは、反復処理を開始すると常に完全な結果を取得します)。
  • Iterator の再起動を実装する必要はありません( Iterable.iterator()は2回呼び出すことができます)。
  • 以前に返されたデータを「覚えていない」ことは、メモリ要件がかなり低く抑えられることを意味します。

また、いくつかの欠点もあります。

  • あなたの Iterator 実装は、JDBCリソースをバインドするため、効果的に外部リソースになります。何らかの方法で「閉じる」必要があります。 Iterator が長時間ハングした場合、その はJDBCの Connection Iterator が完了するまでプールに戻すことはできません)。

もう一つの方法は、必要に応じてデータの端数を遅く復元する List (または Collection )を実装することです。これは使用するほうがいいかもしれませんが、構築するのはかなり複雑です(正しく!)。また、メモリの制約が重要な場合は、以前に復元したオブジェクトを破棄するためのメカニズムを追加する必要があります。

3
追加された
そして、(あなたが言及したような)別の方法は、オフセットを覚えておき、 SELECT ... LIMIT M、N を使って必要な位置にスクロールさせることです。もちろん、情報は時間の経過とともに変更される可能性があります(別のトランザクションで新しい行が挿入または削除されている)が、この方法ではJDBC接続を閉じることができ、DBサーバーは1分あたりのトランザクション数を増やすことができます。
追加された 著者 dma_k,

私は、私のアプリケーションの1つで、Joachimが提案したアプローチを実装しました。 ResultSet ラッパー実装の場合、 ResultSet メソッドを閉じた destroy()メソッドを含む DestroyableIterator /code> (一部のライブラリはこのインタフェースを提供していますが、私は3行のインタフェース定義のためにライブラリ依存性を導入する点は見当たりませんでした。)

また、Iteratorの next()およびを使ってそれらを伝播するために、 SQLException をキャッチし、それらを(未チェック)Spring DataAccessException hasNext()メソッドを使用します。

リソースを保持することに関するポイントは有効なものです。私は DestroyableIterator を使用してアプリケーションコードを制御していましたので、ライブの ResultSet を長時間保持することを避けるためにさまざまなタイムアウト機構がありました。

1
追加された
Java 7以上では、 destroy()の代わりに AutoClosable を実装し、余分なアームブロックの甘さのために close()を使用することをおすすめします。
追加された 著者 Joachim Sauer,
はい、そうです: DestroyableIteratorAutoClosable を実装させましょう(その時点で、名前を AutoClosableIterator ;-)に変更します)
追加された 著者 Joachim Sauer,
ただ、あなたはinstanceofを使ってAutoCloseableをテストしなければなりません。おそらく2つのインターフェースをAutoCloseableIteratorとして統合する価値はありますか?
追加された 著者 Adamski,