1概要

このチュートリアルでは、Hibernateの__load()メソッドとの関連でプロキシがどのようなものであるかを見ていきます。

Hibernateに慣れていない読者は、まずhttps://www.baeldung.com/hibernate-4-spring[basics]に慣れることを検討してください。


2プロキシと

load()

メソッドの簡単な紹介

  • 定義により、https://www.dictionary.com/browse/proxy[proxy]は、「代理人または他の代理人として行動することを許可された機能」です。

これは、

Session.load()

を呼び出して、目的のエンティティクラスの初期化されたプロキシと呼ばれるものを作成するときにHibernateに適用されます。

簡単に言うと、Hibernateは

CGLib

ライブラリを使って、私たちのエンティティクラスをサブクラス化します。

@ Id

メソッド以外のプロキシ実装は、インスタンスを生成するために他のすべてのプロパティメソッドをHibernateセッションに委任します。

public class HibernateProxy extends MyEntity {
    private MyEntity target;

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

  • このサブクラスは、データベースに直接問い合わせる代わりに返されるものです。

いずれかのエンティティメソッドが呼び出されると、エンティティがロードされ、その時点で__初期化プロキシになります。


3プロキシとLazy

__load

__ing


3.1. 単一のエンティティ

「従業員」を実体として考えてみましょう。はじめに、他のテーブルとは関係がないと仮定します。


Session.load()

を使用して

Employee

をインスタンス化すると、次のようになります。

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

それからHibernateは

Employee

の初期化されていないプロキシを作成します。** それは我々がそれに与えたIDを含みますが、そうでなければまだデータベースにヒットしていないので他の値を持ちません。

ただし、

albert

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

String firstName = albert.getFirstName();

それからHibernateは

employee

データベーステーブルに主キー1を持つエンティティを問い合わせ、対応する行から彼のプロパティを持つ

albert

を生成します。

行が見つからなかった場合、Hibernateは

ObjectNotFoundException

をスローします。


3.2. 一対多の関係

それでは、

__ Company


エンティティも作成しましょう。ここで


Company


は多数の

Employeesを持ちます。

public class Company {
    private String name;
    private Set<Employee> 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()は常に初期化されていないプロキシを私たちに与えるわけではありません。実際、https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#load(java.lang.Class,%20java.io.Serializable)[

Session ____java doc]私たちに思い出させる(強調を追加):

このメソッドは、識別子でないメソッドがアクセスされたときにオンデマンドで初期化されたプロキシインスタンスを返すことができる。

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


__従業員エンティティで

@ 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


on

catherine__を呼び出すと、

String cathy = catherine.getFirstName();

  • その後、実際には、Hibernateは3人全員を一度にロードして、3人全員を初期化済みプロキシにすることを決定する場合があります。

それから、

darrell

のファーストネームを呼び出すと、

String darrell = darrell.getFirstName();

そうすれば** Hibernateはデータベースにまったくアクセスしません。

===

5熱心なロード

====

5.1.

get()


を使う

私たちはプロキシを完全に迂回してHibernateに

Session.get()

を使って本物をロードするように依頼することもできます。

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

  • これはプロキシを返すのではなく、すぐにデータベースを呼び出します。

  • 実際には、

    ObjectNotFoundException

    の代わりに、

    __ finniganが存在しない場合は

    null__を返します。

====

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


get()

は便利ですが、

load()

はデータベース上ではより軽量になります。

たとえば、

__gerald

__が新会社に勤務するとしましょう。

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のために

load()を呼び出すことは賢明です。


Company



get()

を呼び出した場合は、そのすべてのデータをデータベースから不必要にロードしたことになります。**

===

6. 結論

この記事では、

Hibernate

プロキシがどのように機能するのか、そしてこれがエンティティとそれらの関係を持つ

load

メソッドにどのように影響するのかを簡単に学びました。

また、

load()

が__get()とどう違うのかを簡単に見てみました。

いつも通り、チュートリアルに付随する完全なソースコードは
利用可能

https://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5

[over
GitHubで。