Hibernate 基準と FetchMode.JOIN によるページネーション
-
28-10-2019 - |
質問
「プレイヤー」と「アイテム」という 2 つのテーブルがあります。プレイヤーはアイテムのリストを持っています。ページネーションを使用して、プレーヤーとそのすべてのアイテムを取得したいと考えています。アイテムの数に関係なく、プレイヤーに基づいてページネーションをしたいと考えています。
そこで私は次のようなことをします:
Criteria c = session.createCriteria(Players.class).setFetchMode("items", FetchMode.JOIN);
c.addOrder(Order.asc("playerID"));
c.setFirstResult(0);
c.setMaxResults(25);
List<Player> players = c.list();
これにより、最初の 25 人のプレイヤーが提供されるのでしょうか、それとも最初の 25 個のアイテム (プレイヤーごとにグループ化された) が提供されるのでしょうか?この動作は JPA クエリの場合と同様に未定義なのか、それとも保証された答えがあるのか疑問に思っています。
それはともかく、最初の 25 人のプレイヤー、または最初の 25 人のプレイヤーとアイテムの組み合わせ (プレイヤー ID、アイテム ID の順) を取得する条件クエリとは何ですか?
解決
確かに、100% ではありませんが、次のことが行われます。
プレイヤーとアイテムを結合し、playerID で並べ替え、最初の 25 件の結果をすべて 1 つの SQL クエリで取得します。このデータからプレーヤーとアイテムが作成され、合計 25 個のアイテムを持つ任意の数 (25 人以下) のプレーヤーが生成されます。最後のプレイヤーがすべてのアイテムを取得できない場合があります。
25 人のプレイヤーを獲得するには、次のことを避けてください。 FetchMode.JOIN
(N+1 問題を回避するには、マッピング ファイルでバッチサイズを使用します):
List<Player> first25Players = session
.createCriteria(Players.class)
.addOrder(Order.asc("playerID"))
.setMaxResults(25)
.list();
25 個のアイテムを取得するには、プレーヤーではなくアイテムでクエリを開始します。
List<Item> first25Items = session
.createCriteria(Item.class)
.addOrder(Order.asc("player")) // assuming that player is available
.setMaxResults(25)
.list();
アイテムからプレーヤーへのナビゲーションがない場合は、ナビゲーションを追加できます。
他のヒント
Hibernate の「高度な問題」に関する FAQ から:
http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems
また、SetFirstreSult(5)やSetMaxResults(10)などのResultSet Rowベースの「制限」操作が、この種の熱心なフェッチクエリでは機能しない理由も明らかです。結果セットを特定の数の行に制限すると、データをランダムに遮断します。ある日、Hibernateは、setFirstreSult()またはsetMaxResults()を呼び出すと、結合を使用しないでください。それを試してください、あなたのバージョンのhibernateはすでに十分に賢いかもしれません。そうでない場合は、2つのクエリを作成します。1つは制限用に、もう1つは熱心なフェッチをするために書きます。
つまり、Hibernate はこれをサポートしていません。賢明で Hibernate がどのように実装されているかを知っていれば、setFirstResult と setMaxResults がどのような場合でもページネーションなどのリモート操作を実行しないことが明らかだったはずです。それは明白だったので文書化する必要はありません。