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の最新バージョンはhttps://mvnrepository.com/artifact/org.hibernate/hibernate-core[ここ]にあります。

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 を含めることができます。 積極的なロード戦略では、 User データをロードすると、それに関連するすべての注文もロードされ、メモリに格納されます

しかし、遅延読み込みが有効になっているときに UserLazy 、pull 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 は、上記の例に示すように、getterまたはその他のメソッドを使用して明示的に呼び出された場合にのみ初期化されます。

UserLazy userLazyLoaded = users.get(3);

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

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

遅延ロードにはプロキシオブジェクトが使用され、 orderDetailSet をロードするために別のSQLクエリが起動されます。

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 クラスの実装に渡される前にデータベースからロードされます。

また、関連付けがコレクションクラスとして表される場合(上記の例では Set <OrderDetail> orderDetailSet として表される)、ラッパーが作成されて元のコレクションに置き換えられます。

プロキシデザインパターンの詳細については、https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html[ここ]を参照してください。

8結論

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

高度な専門知識については、Hibernateの公式Webサイトをご覧ください。この記事で説明したコードを入手するには、https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-hibernate4[リポジトリ]をご覧ください。