web-dev-qa-db-ja.com

@ManyToOne関係のJPA FetchType EAGERがデフォルトであるのはなぜですか?

Hibernateソースコードで、ManyToOneマッピングのデフォルトのFetchTypeがEAGERであることに気付きました。一方、OnetoManyマッピングのデフォルトのロードタイプはレイジーです。この背後にある具体的な理由は何ですか?

12
vatsal mevada

JPA 2.0 specから、デフォルトは次のようになります。

OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER

そしてhibernateでは、すべてがLazyです

Hibernate Docsから

デフォルトでは、Hibernateはコレクションには遅延選択フェッチを使用し、単一値の関連付けには遅延プロキシフェッチを使用します。これらのデフォルトは、ほとんどのアプリケーションのほとんどの関連付けに意味があります。

あなたの質問に答えるために、HibernateはJPA標準の実装です。 Hibernateには独自の動作の癖がありますが、Hibernateのドキュメントによると

By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.

したがって、宣言した関係のタイプに関係なく、Hibernateは常に遅延フェッチ戦略を使用してオブジェクトをロードします。

JPA Specは、一般に、ほとんどのアプリケーションがデフォルトでシングルトン関係が熱心である必要があるが、複数値の関係はデフォルトで遅延であると想定しています。

詳しくは こちら を参照してください

26
Ankur Singhal

それらをEAGERに設定する理由は、初期のJPA 1.0設計者が、動的に初期化するプロキシをサポートするようにJPA実装を強制することが非常に強力な要件であると想定していたためです。ただし、プロキシがないとパフォーマンスが大幅に低下するため、すべてのプロバイダーがLAZYアソシエーションをサポートします。

@ManyToOneおよび@OneToOneアソシエーションにデフォルトのEAGERフェッチ戦略を使用するのは コードのにおい です。

この記事 で説明されているように、すべての関連付けをLAZYとして設定し、すべてのHQL/JPQLまたは基準クエリで使用可能なJOIN FETCHディレクティブを使用することをお勧めします。

6
Vlad Mihalcea

Hibernate OneToOneおよびManyToOneでは、明示的に遅延に設定しても、デフォルトでは遅延は発生しません。

例:Parent-> Childという関連付けがあります。デフォルトでは、これはPARENT_ID列がCHILDテーブルにあることを意味します。 ORMは、親が実際に子を持っているか、それともnullであるかを知りません。子がある場合は、オブジェクトを親としてフィールドとして設定する必要があります。 nullの場合、ORMはnullを設定する必要があります。 ORMがNULLかどうかを調べるには、CHILDテーブルを照会する必要があります。とにかくクエリが行われるので、Childが存在する場合、すぐに返すのは理にかなっています。

したがって、MTOまたはOTOを遅延させるには、子が常に存在するようにORMに指示する必要があります(これをオプションではなくa.k.a.必須a.k.a. not-nullにすることにより)。したがって、ORMはそれが常に存在し、Childの代わりにプロキシを設定できることを知っています。

または、PARENTテーブルにCHILD_ID列を保持することもできます。次に、Childがnullの場合、レコードの値もnullになります。ただし、そのためには構成オプション(@JoinColumnなど)を追加する必要があります。これはデフォルトではありません。

manyToOneでレイジーフェッチを使用する場合は、多側のすべてのモデルを取得するクエリを実行するときに結合を使用する必要があります

0
Paul

注意深く見ると、関係がManyキーワードで終わる場合、つまりOneToManyManyToManyの場合、それはLazyであることがわかります。 Oneで終わる場合、つまりManyToOneOneToOneの場合は、Eagerです。つまり、1つのオブジェクトだけをロードする必要がある場合、非常に高速にフェッチされます。しかし、それが多くのオブジェクトをロードしている場合、多くの時間がかかります。したがって、デフォルトで読み込み時間を停止するには、遅延読み込みに設定する必要があります。

0
Mahesh Shimpi