Hibernateのload()メソッド内のプロキシ
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で。