HibernateにおけるJOINとJOIN FETCHの違い

どこで通常のJOINを使い、どこでJOIN FETCHを使うのか理解するのに役立ちます。

例えば、以下の2つのクエリがあるとします。

FROM Employee emp
JOIN emp.department dep

FROM Employee emp
JOIN FETCH emp.department dep

この2つに違いはありますか?もしそうなら、どのような場合にどちらを使えばいいのでしょうか?

ソリューション

この2つのクエリでは、JOINを使用して、少なくとも1つの部門が関連付けられているすべての従業員を照会しています。

しかし、異なる点は、最初のクエリでは、HibernateのEmployesのみを返しています。2つ目のクエリでは、雇用者と関連するすべての部署を返しています。

したがって、2番目のクエリを使用すると、各EmployeeのDepartmentを見るために再度データベースを叩くような新しいクエリを行う必要はありません。

2 番目のクエリは、各従業員の部門が必要であることが確実な場合に使用できます。部署を必要としない場合は、最初のクエリを使用します。

いくつかのWHERE条件(おそらく必要となるもの)を適用する必要がある場合は、このリンクを読むことをお勧めします: https://stackoverflow.com/questions/5816417/how-to-properly-express-jpql-join-fetch-with-where-clause-as-jpa-2-criteriaq

**アップデート

fetchを使用していないのにDepartmentが返ってくるのは、EmployeeとDepartmentの間のマッピング(@OneToMany)がFetchType.EAGERで設定されているためです。この場合、FROM Employee を含む (fetch を含むかどうかにかかわらず) HQL クエリはすべての部門を取得します。すべてのマッピング *ToOne (@ManyToOne および @OneToOne) は、デフォルトでは EAGER であることに注意してください。

解説 (2)

前にコメントで紹介したthis linkでは、この部分を読んでください。

"fetch"ジョインは、1回のセレクトで、アソシエーションや値のコレクションを親オブジェクトとともに初期化することができます。 fetch"joinを使用すると、1つのselectを使用して、関連や値のコレクションを親オブジェクトと共に初期化することができます。 これは特にコレクションの場合に便利です。それは マッピングファイルの外側のjoinと遅延宣言を効果的にオーバーライドします。 マッピングファイル**の外側joinと遅延宣言を効果的に上書きします。

この "JOIN FETCH" は、エンティティ内のコレクションに (fetch = FetchType.LAZY) プロパティを設定した場合に効果を発揮します(下の例)。

そして、それは "when the query should happen" のメソッドにのみ影響します。また、thisも知っておく必要があります。

hibernateは2つの直交する概念を持っています:いつアソシエーションをフェッチするのか、そしてどのように という2つの概念があります。この2つを混同しないようにすることが重要です。我々は フェッチを使用してパフォーマンスを調整します。lazyは、どのようなデータが常に利用可能かという契約を定義するために使用できます。 遅延を使用して、特定のクラスの離脱したインスタンスでどのようなデータが常に利用可能であるかの契約を定義することができます。 クラスの切り離されたインスタンスで常に利用可能なデータの契約を定義するために使用できます。

関連付けがいつフェッチされるか --> あなたの"FETCH" タイプ

どのように取得されるか --> Join/select/Subselect/Batch

あなたの場合、FETCHが効果を発揮するのは、Employeeの中に部門をセットとして持ち、エンティティの中に以下のようなものがある場合です。

@OneToMany(fetch = FetchType.LAZY)
private Set department;

を使用した場合

FROM Employee emp
JOIN FETCH emp.department dep

fetchを使用しなかった場合は、emp.depを得ることができますが、hibernateはその部門のセットを得るためにデータベースへの別のselectを処理します。

つまり、1回のクエリですべての結果(必要かどうかにかかわらず)を取得したいか(イーガーフェッチ)、必要なときに後からクエリを実行したいか(レイジーフェッチ)という、パフォーマンスチューニングの問題です。

イーガーフェッチングは、小さなデータを1つのセレクト(1つの大きなクエリ)で取得する必要がある場合に使用します。また、後から必要なものを照会する場合には、遅延フェッチを使用します(多数の小さな照会)。

フェッチの使用例

  • 取得しようとしているエンティティの中に、大きな不要なコレクション/セットがない。

  • アプリケーション・サーバからデータベース・サーバまでの通信距離が長く、時間がかかる場合

  • 後日、そのコレクションにアクセスできない時に必要になるかもしれない(トランザクショナルメソッド/クラスの外で

解説 (4)

Dherik : おっしゃることがよくわからないのですが、fetch を使用しない場合、結果は List という型になり、これは Object テーブルのリストを意味し、Employee のリストではありません。

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

fetchを使用した場合、selectは1回だけで、結果は出発者のリストを含むEmployeeのリスト Listとなります。エンティティの遅延宣言を上書きします。

解説 (5)