ハイバネートのキャッシング-ファーストレベルキャッシュ
ハイバネート キャッシング – ファーストレベルキャッシュの実例チュートリアルへようこそ。最近、ハイバネートのアーキテクチャ、ハイバネートマッピング、オブジェクト指向の方法でSQLクエリを発行するためのHQLの使用方法を調べました。今日は、ハイバネートの重要な側面の一つであるハイバネートキャッシュについて見ていきます。
ヒバネイトのキャッシュ
正しく使用すれば、ハイバネートキャッシュはアプリケーションパフォーマンスの向上に非常に役立つことがあります。キャッシュのアイデアは、データベースクエリの数を減らし、それによってアプリケーションの処理時間を短縮することです。ハイバネートにはさまざまな種類のキャッシュが付属しています。
-
- 最初のレベルのキャッシュ:ハイバネートの最初のレベルのキャッシュは、Sessionオブジェクトに関連付けられています。ハイバネートの最初のレベルのキャッシュはデフォルトで有効になっており、無効にする方法はありません。ただし、選択したオブジェクトをキャッシュから削除したり、キャッシュを完全にクリアするための方法がハイバネートに提供されています。セッションにキャッシュされているオブジェクトは他のセッションからは見えず、セッションが閉じられると、キャッシュされたすべてのオブジェクトも失われます。
2番目のレベルのキャッシュ:ハイバネートの2番目のレベルのキャッシュはデフォルトで無効になっていますが、設定を通じて有効にすることもできます。現在、EHCacheとInfinispanはハイバネートの2番目レベルのキャッシュの実装を提供しており、それらを使用することができます。次のハイバネートキャッシュのチュートリアルで詳しく説明します。
クエリキャッシュ:ハイバネートはクエリの結果セットもキャッシュすることができます。ハイバネートのクエリキャッシュは、実際のエンティティの状態をキャッシュしないため、識別子の値と値タイプの結果のみをキャッシュします。そのため、常に2番目のレベルのキャッシュと一緒に使用する必要があります。
ヒベルネートのキャッシング – ファーストレベルキャッシュの例
私のハイバネートのファーストレベルキャッシュの例のプログラムでは、HQLの例と同じ設定を使用していますので、それを確認してテーブルを設定し、ダミーデータで埋めることができます。まずはプログラムとその出力を見てから、Hibernateのファーストレベルキャッシュに関連するいくつかの重要なポイントを説明していきましょう。HibernateCacheExample.javaをご覧ください。
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 HibernateCacheExample {
public static void main(String[] args) throws InterruptedException {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//Get employee with id=1
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//waiting for sometime to change the data in backend
Thread.sleep(10000);
//Fetch same data again, check logs that no query fired
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//Create new session
Session newSession = sessionFactory.openSession();
//Get employee with id=1, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//START: evict example to remove specific object from hibernate first level cache
//Get employee with id=2, first time hence query in logs
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//evict the employee object with id=1
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//since object is removed from first level cache, you will see query in logs
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//this object is still present, so you won't see query in logs
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//END: evict example
//START: clear example to remove everything from first level cache
session.clear();
Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
printData(emp6,7);
Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
printData(emp7,8);
System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
tx.commit();
sessionFactory.close();
}
private static void printData(Employee emp, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
}
}
上記の例を実行すると、出力には多くのハイバネート関連の情報が含まれています。しかし、私たちは主に私たちのコードが出力する情報やハイバネートがデータを読み込むために発行するクエリに興味があります。出力のスニペットは以下のようになります。
Hibernate Configuration loaded
Hibernate serviceRegistry created
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=?
1:: Name=Pankaj, Zipcode=95129
2:: Name=Pankaj, Zipcode=95129
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=?
3:: Name=PankajK, Zipcode=95129
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=?
4:: Name=David, Zipcode=95051
Session Contains Employee with id=1?false
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=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
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=?
7:: Name=Pankaj, Zipcode=95129
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=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true
HibernateにおけるFirst Level Cacheの重要なポイント
上記のプログラムから導き出せるHibernateの一次キャッシュに関する重要ポイントは以下の通りです:
-
- デフォルトでは、Hibernateの第一レベルキャッシュは有効です。このため、設定は必要ありません。
-
- Hibernateの第一レベルキャッシュはセッションに固有であり、同じセッションで同じデータを取得する場合はクエリが発行されませんが、別のセッションではクエリが発行されてデータがロードされます。
-
- Hibernateの第一レベルキャッシュには古い値が残ることがあります。上記の例でわかるように、プログラムを10秒間スリープさせてその間にデータベースで値(名前をPankajからPankajKに変更)を更新しましたが、同じセッションでは反映されませんでした。しかし、別のセッションでは更新された値が取得できました。
-
- Hibernateの第一レベルキャッシュから単一のオブジェクトを削除するには、session evict()メソッドを使用できます。
-
- キャッシュをクリアするには、session clear()メソッドを使用できます。つまり、キャッシュ内のすべてのオブジェクトが削除されます。
-
- オブジェクトがHibernateキャッシュに存在するかどうかを確認するには、session contains()メソッドを使用できます。キャッシュ内でオブジェクトが見つかれば、trueを返し、そうでなければfalseを返します。
- Hibernateはすべてのオブジェクトをセッションの第一レベルキャッシュにキャッシュするため、大量のクエリやバッチ更新を実行する際には定期的にキャッシュをクリアすることが必要です。これによりメモリの問題を回避できます。
これがハイバネートのキャッシュとファーストレベルキャッシュの例の全てです。後の投稿では、ハイバネートのセカンドレベルキャッシュであるEHCacheの実装を見ていきます。