通常のJOINを使用する場所とJOIN FETCHをどこで使用するかを教えてください。
たとえば、次の2つのクエリがある場合
FROM Employee emp
JOIN emp.department dep
そして
FROM Employee emp
JOIN FETCH emp.department dep
それらの間に違いはありますか?はいの場合、どちらを使用しますか?
通常のJOINを使用する場所とJOIN FETCHをどこで使用するかを教えてください。
たとえば、次の2つのクエリがある場合
FROM Employee emp
JOIN emp.department dep
そして
FROM Employee emp
JOIN FETCH emp.department dep
それらの間に違いはありますか?はいの場合、どちらを使用しますか?
回答:
この2つのクエリでは、JOINを使用して、少なくとも1つの部門が関連付けられているすべての従業員をクエリしています。
しかし、違いは次のとおりです。最初のクエリでは、HibernateのEmployesのみが返されます。2番目のクエリでは、従業員と関連するすべての部門を返しています。
したがって、2番目のクエリを使用する場合、データベースを再度ヒットして各従業員の部門を表示するために新しいクエリを実行する必要はありません。
各従業員の部門が必要であることが確実な場合は、2番目のクエリを使用できます。部門が必要ない場合は、最初のクエリを使用します。
WHERE条件(おそらく必要になるもの)を適用する必要がある場合は、このリンクをお読みになることをお勧めします。JPQLの "join fetch"を "where"句でJPA 2 CriteriaQueryとして適切に表現するにはどうすればよいですか。
更新
使用せずfetch
、Departmentsが引き続き返される場合は、EmployeeとDepartment(a @OneToMany
)の間のマッピングがで設定されているためFetchType.EAGER
です。この場合、すべてのHQL(with fetch
またはnot)クエリFROM Employee
はすべての部門をもたらします。すべてのマッピング* ToOne(@ManyToOne
および@OneToOne
)は、デフォルトでEAGERであることに注意してください。
fetch
(例を使用して)Department属性で注文したい場合に使用する必要があることに言及する価値があります。それ以外の場合、(少なくともPGで有効)あなたは得るかもしれませんERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
私が前にコメントで述べたこのリンクで、この部分を読んでください:
「フェッチ」結合を使用すると、値の関連付けまたはコレクションを、単一の選択を使用して親オブジェクトとともに初期化できます。これは、コレクションの場合に特に役立ちます。これは、関連付けとコレクションのマッピングファイルの外部結合と遅延宣言を効果的にオーバーライドします。
この「JOIN FETCH」は、エンティティ内のコレクションの(fetch = FetchType.LAZY)プロパティがある場合に効果があります(以下の例)。
そしてそれは「クエリがいつ起こるべきか」という方法にのみ影響します。そして、あなたもこれを知っている必要があります:
hibernateには2つの直交する概念があります。関連付けがいつフェッチされ、どのようにフェッチされるかです。それらを混同しないようにすることが重要です。フェッチを使用してパフォーマンスを調整します。lazyを使用して、特定のクラスのデタッチされたインスタンスで常に使用可能なデータのコントラクトを定義できます。
関連付けがフェッチされるのはいつですか->「フェッチ」タイプ
フェッチ方法->結合/選択/副選択/バッチ
あなたの場合、エンティティ内に次のようなEmployee内のセットとして部門がある場合にのみ、FETCHが効果を発揮します。
@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;
あなたが使うとき
FROM Employee emp
JOIN FETCH emp.department dep
あなたが取得emp
しemp.dep
ます。フェッチを使用しなかっemp.dep
た場合でも取得できますが、Hibernateはデータベースに対して別の選択を処理して、その部門のセットを取得します。
したがって、パフォーマンスチューニングの問題であり、1つのクエリですべての結果(必要かどうか)を取得したい(イージーフェッチ)、または必要なときに後者をクエリしたい(遅延フェッチ)ことについてです。
1つの選択(1つの大きなクエリ)で小さなデータを取得する必要がある場合は、熱心なフェッチを使用します。または、遅延フェッチを使用して、必要なものをクエリします(多くの小さいクエリ)。
次の場合にフェッチを使用します。
取得しようとしているエンティティ内に、不要な大きなコレクション/セットはありません
アプリケーションサーバーからデータベースサーバーへの通信が遠すぎて時間がかかる
あなたはそれへのアクセス(持っていないときは、そのコレクションは、後者の必要があるかもしれない外の取引方法/クラス)
List
代わりにだった場合、部門は依然として熱心にフェッチされますかSet
?
FETCH
JPQLステートメントでキーワードを使用することは、熱心に取得されたプロパティを意味しますか?
JOIN
エンティティの関連付けに対して使用する場合、JPAは、生成されたSQLステートメントで、親エンティティと子エンティティテーブルの間にJOINを生成します。
したがって、例として、このJPQLクエリを実行すると、次のようになります。
FROM Employee emp
JOIN emp.department dep
Hibernateは次のSQLステートメントを生成します。
SELECT emp.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
SQL
SELECT
句にはemployee
テーブルの列のみが含まれ、列は含まれないことに注意してくださいdepartment
。department
テーブルの列を取得するには、のJOIN FETCH
代わりにを使用する必要がありますJOIN
。
そのためJOIN
、JOIN FETCH
ではSELECT
、生成されたSQLステートメントの句に結合テーブルの列を投影できます。
したがって、あなたの例では、このJPQLクエリを実行するとき:
FROM Employee emp
JOIN FETCH emp.department dep
Hibernateは次のSQLステートメントを生成します。
SELECT emp.*, dept.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
今回
department
は、FROM
JPQL句にリストされているエンティティに関連付けられている列だけでなく、テーブルの列も選択されていることに注意してください。
また、フェッチするメインエンティティと共にフェッチ戦略を使用してエンティティの関連付けを初期化できるJOIN FETCH
ため、LazyInitializationException
Hibernateを使用する場合に対処する優れた方法FetchType.LAZY
です。
あなたがしている場合@oneToOne
にセットをマッピングFetchType.LAZY
Hibernateは何をするか(あなたは部門は従業員オブジェクトの一部としてロードするオブジェクト必要があるため)されていて、2番目のクエリを使用し、それが部門は、それはDBからのフェッチごとに個別のEmployeeオブジェクトのためのオブジェクトを取得するためにクエリを発行します。
その後、コードでEmployeeからDepartmentへの単一値の関連付けを介してDepartmentオブジェクトにアクセスし、Hibernateはクエリを発行して、指定されたEmployeeのDepartmentオブジェクトをフェッチしません。
Hibernateは、フェッチした従業員の数に等しいクエリを発行することに注意してください。すべてのEmployeeオブジェクトのDepartmentオブジェクトにアクセスする場合、Hibernateは上記の両方のクエリで同じ数のクエリを発行します
Dherik:何を言っているのかわかりません。フェッチを使用しない場合、結果のタイプは:List<Object[ ]>
Employeeのリストではなく、Objectテーブルのリストになります。
Object[0] refers an Employee entity
Object[1] refers a Departement entity
フェッチを使用すると、選択は1つだけになり、結果はList<Employee>
部門のリストを含む従業員のリストになります。エンティティの遅延宣言をオーバーライドします。
fetch
、クエリは従業員のみを返します。この場合でも、Departmentsが引き続き返されるのは、EmployeeとDepartmentの間のマッピング(@OneToMany)がFetchType.EAGERで設定されているためです。この場合、すべてのHQL(with fetch
またはnot)クエリFROM Employee
はすべての部門をもたらします。
@OneToMany(fetch = FetchType.EAGER
)の場合にのみ発生します。そうでない場合、部門は返却されません。
select
が、HQLでどのように作成されたかを示します。お試しくださいSELECT emp FROM Employee emp JOIN FETCH emp.department dep
。JPA / Hibernateは、パーツを省略した場合のreturn a List
の動作Object[]
を備えていますSELECT
。