Hibernateのload()メソッド内のプロキシ

Hibernate load()メソッドのプロキシ

1. 概要

このチュートリアルでは、Hibernateのload()メソッドのコンテキストでプロキシが何であるかを確認します。

Hibernateを初めて使用する読者は、最初にbasicsに慣れることを検討してください。

2. プロキシとload()メソッドの簡単な紹介

By definition, a proxy is “a function authorized to act as the deputy or substitute for another”

これは、Session.load()を呼び出して目的のエンティティクラスのuninitialized proxy と呼ばれるものを作成するときに、Hibernateに適用されます。

簡単に言うと、HibernateはCGLibライブラリを使用してエンティティクラスをサブクラス化します。 @Idメソッドを除いて、プロキシ実装は他のすべてのプロパティメソッドをHibernateセッションに委任して、インスタンスにデータを入力します。

public class HibernateProxy extends MyEntity {
    private MyEntity target;

    public String getFirstName() {
        if (target == null) {
            target = readFromDatabase();
        }
        return target.getFirstName();
    }
}

このサブクラスは、データベースに直接クエリを実行する代わりに返されるサブクラスになります。

エンティティメソッドの1つが呼び出されると、エンティティが読み込まれ、その時点でinitialized proxy.になります。

3. プロキシとレイジーloading

3.1. 単一のエンティティ

Employee をエンティティとして考えてみましょう。 まず、他のテーブルとは関係がないと仮定します。

Session.load()を使用してEmployeeをインスタンス化する場合:

Employee albert = session.load(Employee.class, new Long(1));

次に、HibernateはEmployee It will contain the ID that we gave it but otherwise will have no other values because we haven’t hit the database yet.の初期化されていないプロキシを作成します

ただし、albertでメソッドを呼び出すと、次のようになります。

String firstName = albert.getFirstName();

次に、Hibernateはemployeeデータベーステーブルで主キーが1のエンティティをクエリし、対応する行のプロパティをalbertに入力します。

行が見つからない場合、HibernateはObjectNotFoundExceptionをスローします。

3.2. 1対多の関係

それでは、Company entityも作成しましょう。ここで、Company は多くのEmployees:を共有します。

public class Company {
    private String name;
    private Set employees;
}

今回は会社でSession.load() を使用する場合:

Company bizco = session.load(Company.class, new Long(1));
String name = bizco.getName();

次に、従業員のセットが少し異なることを除いて、会社のプロパティが以前と同じように入力されます。

ほら、会社の行のみを照会しましたが、フェッチ戦略に応じて、getEmployeesを呼び出すまで、プロキシは従業員をそのままにしておきます。

3.3. 多対1の関係

ケースは反対方向でも同様です:

public class Employee {
    private String firstName;
    private Company workplace;
}

load()を再度使用する場合:

Employee bob = session.load(Employee.class, new Long(2));
String firstName = bob.getFirstName();

bob が初期化され、実際には、フェッチ戦略に応じて、workplaceが初期化されていないプロキシに設定されます。

4. 怠惰な読み込み

現在、load() は、初期化されていないプロキシを常に提供するとは限りません。 実際、Session java docは私たちに思い出させます(強調が追加されました):

このメソッドmightは、識別子以外のメソッドにアクセスすると、オンデマンドで初期化されるプロキシインスタンスを返します。

これが発生する可能性のある簡単な例は、バッチサイズです。

Employee entityで@BatchSizeを使用しているとしましょう。

@Entity
@BatchSize(size=5)
class Employee {
    // ...
}

そして今回は3人の従業員がいます。

Employee catherine = session.load(Employee.class, new Long(3));
Employee darrell = session.load(Employee.class, new Long(4));
Employee emma = session.load(Employee.class, new Long(5));

getFirstName oncatherineと呼ぶ場合:

String cathy = catherine.getFirstName();

次に、実際には、Hibernateは3人の従業員すべてを一度にロードして、3人すべてを初期化されたプロキシに変えることを決定する場合があります。

そして、darrellの名を呼び出すと、次のようになります。

String darrell = darrell.getFirstName();

次にHibernate doesn’t hit the database at all.

5. 熱心なロード

5.1. get()の使用

プロキシを完全にバイパスし、Session.get()を使用してHibernateに本物をロードするように依頼することもできます。

Employee finnigan = session.get(Employee.class, new Long(6));

これにより、プロキシを返す代わりに、データベースがすぐに呼び出されます。

実際、finnigan が存在しない場合は、ObjectNotFoundExceptionの代わりにnullが返されます。

5.2. パフォーマンスへの影響

get()は便利ですが、データベースではload()を軽くすることができます。

たとえば、gerald isが新しい会社で働くとしましょう。

Employee gerald = session.get(Employee.class, new Long(7));
Company worldco = (Company) session.load(Company.class, new Long(2));
employee.setCompany(worldco);
session.save(employee);

この状況ではemployee recordのみを変更することがわかっているので、Company isのload()を呼び出す,は賢明です。

Companyget()を呼び出すと、データベースからすべてのデータが不必要に読み込まれます。

6. 結論

この記事では、Hibernateプロキシがどのように機能し、これがエンティティとその関係でloadメソッドにどのように影響するかを簡単に学びました。

また、load()get().の違いを簡単に確認しました

いつものように、チュートリアルに付属する完全なソースコードは利用可能ですover on GitHub.