ヒベルネイトのSessionのget()とload()の違いと例について説明します。get()メソッドとは、データベースから指定されたオブジェクトを読み込むためのメソッドです。もし該当するオブジェクトが存在しない場合は、nullが返されます。例えば、以下のように使用します。例:Person person = session.get(Person.class, 1);もしデータベースにIDが1のPersonオブジェクトが存在すれば、そのオブジェクトが返されます。もし存在しなければ、nullが返されます。一方、load()メソッドは、遅延読み込み(Lazy Loading)を利用してオブジェクトを取得します。つまり、実際にオブジェクトを使用する時までデータベースへのアクセスを遅延させることができます。例えば、以下のように使用します。例:Person person = session.load(Person.class, 1);load()メソッドでは、データベースにアクセスせずに代わりにプロキシ(Proxy)オブジェクトを返します。実際にオブジェクトのプロパティにアクセスする時に初めてデータベースへのアクセスが行われます。以上が、get()メソッドとload()メソッドの違いとそれぞれの例です。
ハイバネートセッションは、データベースからデータを取得するための異なるメソッドを提供しています。そのうちの2つは、get()とload()です。これらにはさまざまな状況で使用できるオーバーロードされたメソッドもたくさんあります。最初に見る限り、get()とload()は似ているように思えますが、実際にはいくつかの違いがあります。以下の簡単な例でそれを見てみましょう。
package com.scdev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.scdev.hibernate.model.Employee;
import com.scdev.hibernate.util.HibernateUtil;
public class HibernateGetVsLoad {
public static void main(String[] args) {
//Prep Work
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Get Example
Employee emp = (Employee) session.get(Employee.class, new Long(2));
System.out.println("Employee get called");
System.out.println("Employee ID= "+emp.getId());
System.out.println("Employee Get Details:: "+emp+"\n");
//load Example
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
System.out.println("Employee load called");
System.out.println("Employee ID= "+emp1.getId());
System.out.println("Employee load Details:: "+emp1+"\n");
//Close resources
tx.commit();
sessionFactory.close();
}
}
上記のコードを実行すると、以下の出力が生成されます。
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee get called
Employee ID= 2
Employee Get Details:: Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}
Employee load called
Employee ID= 1
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee load Details:: Id= 1, Name= Pankaj, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}
出力から明らかなように、get()はデータベースまたはHibernateキャッシュからオブジェクトを取得して返すのに対し、load()は実際に存在しない可能性のあるオブジェクトの参照を返します。オブジェクトの他のプロパティにアクセスすると、データはデータベースまたはキャッシュからのみロードされます。では、データベースに存在しないデータを取得してみましょう。
//Get Example
try{
Employee emp = (Employee) session.get(Employee.class, new Long(200));
System.out.println("Employee get called");
if(emp != null){
System.out.println("Employee GET ID= "+emp.getId());
System.out.println("Employee Get Details:: "+emp+"\n");
}
}catch(Exception e){
e.printStackTrace();
}
//load Example
try{
Employee emp1 = (Employee) session.load(Employee.class, new Long(100));
System.out.println("Employee load called");
System.out.println("Employee LOAD ID= "+emp1.getId());
System.out.println("Employee load Details:: "+emp1+"\n");
}catch(Exception e){
e.printStackTrace();
}
上記のコードは、次の出力を生成します。
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee get called
Employee load called
Employee LOAD ID= 100
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.scdev.hibernate.model.Employee#100]
at org.hibernate.internal.SessionFactoryImpl$1$1.handleEntityNotFound(SessionFactoryImpl.java:253)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:262)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.scdev.hibernate.model.Employee_$$_jvst407_1.toString(Employee_$$_jvst407_1.java)
at java.lang.String.valueOf(String.java:2847)
at java.lang.StringBuilder.append(StringBuilder.java:128)
at com.scdev.hibernate.main.HibernateExample.main(HibernateExample.java:36)
出力を注意深く見ると、存在しないデータを取得するためにget()を使用した場合、nullが返されます。これは、呼び出されるとすぐにデータをロードしようとするため、理にかなっています。load()を使用すると、IDを印刷することができますが、他のフィールドにアクセスしようとすると、データベースのクエリが発生し、指定された識別子で該当するレコードが見つからない場合、org.hibernate.ObjectNotFoundExceptionがスローされます。これはHibernate固有の実行時例外であり、明示的にキャッチする必要はありません。いくつかのオーバーロードされたメソッドにも目を向けましょう。上記のget()とload()メソッドは以下のようにも書くことができました。
Employee emp = (Employee) session.get("com.scdev.hibernate.model.Employee", new Long(2));
Employee emp1 = (Employee) session.load("com.scdev.hibernate.model.Employee", new Long(1));
Employee emp2 = new Employee();
session.load(emp1, new Long(1));
ロックオプション引数を使用した他の方法もありますが、私は使ったことがありません。引数として完全なクラス名を渡す必要があることに注意してください。上記の説明に基づいて、get()とload()の間には次のような違いがあります。
-
- get()が呼び出されるとすぐにデータをロードしますが、load()はプロキシオブジェクトを返し、データは実際に必要な時にのみロードされるため、遅延ローディングをサポートするload()の方が良いです。
-
- データが見つからない場合にはload()が例外をスローするため、データが存在することがわかっている場合にのみ使用するべきです。
- データベースにデータが存在することを確認したい場合には、get()を使用するべきです。
ハイバネーションのgetメソッドとloadメソッドについては以上です。いくつかの疑問を解消し、異なるシナリオでどちらを使用するかの決定に役立つことを願っています。