Hibernateでの熱心な/遅延読み込み
1. 概要
ORMを使用する場合、データのフェッチ/ロードは、熱心なものと怠惰なものの2つのタイプに分類できます。
このクイックチュートリアルでは、違いを指摘し、Hibernateでこれらをどのように使用できるかを示します。
2. Mavenの依存関係
Hibernateを使用するために、最初にpom.xmlで主な依存関係を定義しましょう。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.2.Final</version>
</dependency>
Hibernateの最新バージョンはここにあります。
3. 熱心で遅延読み込み
ここで最初に説明する必要があるのは、遅延読み込みと熱心な読み込みとは何かです。
- Eager Loading は、データの初期化がその場で行われるデザインパターンです。
- Lazy Loading は、オブジェクトの初期化を可能な限り延期するために使用するデザインパターンです。
これがどのように機能するか見てみましょう。
まず、UserLazyクラスを見てみましょう。
@Entity
@Table(name = "USER")
public class UserLazy implements Serializable {
@Id
@GeneratedValue
@Column(name = "USER_ID")
private Long userId;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<OrderDetail> orderDetail = new HashSet();
// standard setters and getters
// also override equals and hashcode
}
次に、OrderDetailクラスが表示されます。
@Entity
@Table (name = "USER_ORDER")
public class OrderDetail implements Serializable {
@Id
@GeneratedValue
@Column(name="ORDER_ID")
private Long orderId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="USER_ID")
private UserLazy user;
// standard setters and getters
// also override equals and hashcode
}
1つのUserに複数のOrderDetailsを含めることができます。積極的な読み込み戦略では、ユーザーデータを読み込むと、それに関連付けられているすべての注文も読み込まれ、メモリ。
ただし、遅延読み込みを有効にした場合、 UserLazy をプルアップすると、 OrderDetail データは初期化されず、明示的に呼び出すまでメモリに読み込まれません。
次のセクションでは、Hibernateで例を実装する方法を説明します。
4. 構成のロード
Hibernateでフェッチ戦略を構成する方法を見てみましょう。
このアノテーションパラメータを使用して、遅延読み込みを有効にできます。
fetch = FetchType.LAZY
Eager Fetchingの場合、次のパラメーターを使用します。
fetch = FetchType.EAGER
Eager Loadingを設定するために、UserLazyのツインクラスUserEagerを使用しました。
次のセクションでは、2つのタイプのフェッチの違いを見ていきます。
5. 違い
前述したように、2種類のフェッチの主な違いは、データがメモリにロードされる瞬間です。
みてみましょう:
List<UserLazy> users = sessionLazy.createQuery("From UserLazy").list();
UserLazy userLazyLoaded = users.get(3);
return (userLazyLoaded.getOrderDetail());
遅延初期化アプローチでは、 orderDetailSet は、ゲッターまたはその他のメソッドを使用して明示的に呼び出した場合にのみ初期化されます。
UserLazy userLazyLoaded = users.get(3);
しかし、 UserEager での熱心なアプローチでは、最初の行ですぐに初期化されます。
List<UserEager> user = sessionEager.createQuery("From UserEager").list();
遅延読み込みの場合、プロキシオブジェクトを使用し、別のSQLクエリを実行してorderDetailSetを読み込みます。
プロキシや遅延読み込みを無効にするという考えは、Hibernateでは悪い習慣と見なされています。 その結果、必要性に関係なく、大量のデータをフェッチして保存する可能性があります。
次の方法を使用して、機能をテストできます。
Hibernate.isInitialized(orderDetailSet);
次に、どちらの場合でも生成されるクエリを見てみましょう。
<property name="show_sql">true</property>
fetching.hbm.xml の上記の設定は、生成されたSQLクエリを示しています。 コンソール出力を見ると、生成されたクエリを確認できます。
遅延読み込みの場合、Userデータを読み込むために生成されるクエリは次のとおりです。
select user0_.USER_ID as USER_ID1_0_, ... from USER user0_
ただし、積極的な読み込みでは、USER_ORDERで結合が行われていることがわかりました。
select orderdetai0_.USER_ID as USER_ID4_0_0_, orderdetai0_.ORDER_ID as ORDER_ID1_1_0_, orderdetai0_ ...
from USER_ORDER orderdetai0_ where orderdetai0_.USER_ID=?
上記のクエリは、すべての Users に対して生成されるため、他のアプローチよりもはるかに多くのメモリを使用します。
6. 長所と短所
6.1. 遅延読み込み
利点:
- 他のアプローチよりもはるかに短い初期ロード時間
- 他のアプローチよりも少ないメモリ消費
短所:
- 初期化の遅延は、不要な瞬間のパフォーマンスに影響を与える可能性があります。
- 場合によっては、遅延初期化されたオブジェクトを特別な注意を払って処理する必要があります。そうしないと、例外が発生する可能性があります。
6.2. 熱心な読み込み
利点:
- 初期化の遅延に関連するパフォーマンスへの影響はありません
短所:
- 初期読み込み時間が長い
- 不要なデータをロードしすぎると、パフォーマンスに影響を与える可能性があります
7. Hibernateでの遅延読み込み
Hibernateは、クラスのプロキシ実装を提供することにより、エンティティとアソシエーションに遅延読み込みアプローチを適用します。
Hibernateは、エンティティのクラスから派生したプロキシでエンティティを置き換えることにより、エンティティへの呼び出しをインターセプトします。 この例では、制御が User クラスの実装に渡される前に、欠落している要求された情報がデータベースからロードされます。
アソシエーションがコレクションクラスとして表される場合(上記の例では、次のように表されることにも注意してください)。 設定
プロキシデザインパターンの詳細については、こちらを参照してください。
8. 結論
この記事では、Hibernateで使用される2つの主要なタイプのフェッチの例を示しました。
高度な専門知識については、Hibernateの公式Webサイトを確認してください。
この記事で説明されているコードを入手するには、このリポジトリをご覧ください。