Hibernateで熱心/遅延読み込み

Eager/Lazy Loading In Hibernate

1. 前書き

ORMを使用する場合、データの取得/読み込みは2種類に分類できます:熱心と怠laです。

この簡単な記事では、違いを指摘し、それらをHibernateで使用できることを示します。

2. Mavenの依存関係

Hibernateを使用するために、最初にpom.xmlで主な依存関係を定義しましょう。


    org.hibernate
    hibernate-core
    5.2.2.Final

Hibernateの最新バージョンはhereにあります。

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 = 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を含めることができます。 In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory

ただし、遅延読み込みが有効になっている場合、UserLazyをプルアップすると、明示的な呼び出しが行われるまで、OrderDetailデータは初期化されず、メモリに読み込まれません。

次のセクションでは、上記の例がHibernateでどのように実装されるかを見ていきます。

4. 構成のロード

このセクションでは、Hibernateでフェッチ戦略を設定する方法を見ていきます。 前のセクションの例を再利用します。

遅延読み込みは、次の注釈パラメーターを使用して簡単に有効にできます。

fetch = FetchType.LAZY

Eager Fetchingを使用するには、次のパラメーターが使用されます。

fetch = FetchType.EAGER

Eager Loadingを設定するために、UserEagerと呼ばれるUserLazyのツインクラスを使用しました。

次のセクションでは、2つのタイプのフェッチの違いを見ていきます。

5. 違い

前述したように、2つのタイプのフェッチの主な違いは、データがメモリにロードされる瞬間です。

この例を見てみましょう。

List users = sessionLazy.createQuery("From UserLazy").list();
UserLazy userLazyLoaded = users.get(3);
return (userLazyLoaded.getOrderDetail());

遅延初期化アプローチでは、orderDetailSetは、上記の例に示すように、ゲッターまたはその他のメソッドを使用して明示的に呼び出された場合にのみ初期化されます。

UserLazy userLazyLoaded = users.get(3);

しかし、UserEagerでの熱心なアプローチでは、上記の例の最初の行ですぐに初期化されます。

List user = sessionEager.createQuery("From UserEager").list();

遅延読み込みの場合、プロキシオブジェクトが使用され、orderDetailSetを読み込むために別のSQLクエリが実行されます。

Hibernateでは、プロキシまたは遅延読み込みを無効にするという考えは悪い習慣と見なされます。 その結果、データベースの必要性に関係なく、データベースから大量のデータがフェッチされ、メモリに保存される可能性があります。

上記の機能をテストするには、次の方法を使用できます。

Hibernate.isInitialized(orderDetailSet);

どちらの場合でも生成されるクエリを確認することが重要です。

true

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 applies lazy loading approach on entities and associations by providing a proxy implementation

Hibernateは、エンティティのクラスから派生したプロキシでエンティティを置き換えることにより、エンティティへの呼び出しをインターセプトします。 この例では、要求された情報が欠落している場合、制御がUserクラスの実装に譲渡される前に、データベースからロードされます。

アソシエーションがコレクションクラスとして表される場合(上記の例ではSet<OrderDetail> orderDetailSetとして表される)、ラッパーが作成され、元のコレクションに置き換えられることにも注意してください。

プロキシデザインパターンの詳細については、hereを参照してください。

8. 結論

この記事では、Hibernateで使用されるフェッチの2つの主要なタイプの例を示しました。

高度な専門知識については、Hibernateの公式Webサイトをご覧ください。 この記事で説明されているコードを入手するには、このrepositoryをご覧ください。