1. 程式人生 > >hibernate 快取介紹與快取使用方式

hibernate 快取介紹與快取使用方式

hibernate中提供了兩級快取,一級快取是Session級別的快取,它屬於事務範圍的快取,該級快取由hibernate管理,應用程式無需干預;二級快取是SessionFactory級別的快取,該級快取可以進行配置和更改,並且可以動態載入和解除安裝,hibernate還為查詢結果提供了一個查詢快取,它依賴於二級快取;

一,快取的概念

快取是位於應用程式和永久性資料儲存源之間用於臨時存放複製資料的記憶體區域,快取可以降低應用程式之間讀寫永久性資料儲存源的次數,從而提高應用程式的執行效能;

hibernate在查詢資料時,首先會到快取中查詢,如果找到就直接使用,找不到時才從永久性資料儲存源中檢索,因此,把頻繁使用的資料載入到快取中,可以減少應用程式對永久性資料儲存源的訪問,使應用程式的執行效能得以提升;

二,快取的範圍

快取範圍決定了快取的生命週期,快取範圍分為3類:

1>事務範圍

快取只能被當前事務訪問,快取的生命週期依賴於事務的生命週期,事務結束時,快取的生命週期也結束了;

2>程序範圍

快取被程序內的所有事務共享,這些事務會併發訪問快取,需要對快取採用必要的事務隔離機制,快取的生命週期取決與程序的生命週期,程序結束,快取的生命週期也結束了;

3>叢集範圍

快取被一個或多個計算機的程序共享,快取中的資料被複制到叢集中的每個進行節點,程序間通過遠端通訊來保證快取中資料的一致性;

在查詢時,如果在事務範圍內的快取中沒有找到,可以到程序範圍或叢集範圍的快取中查詢,如果還沒找到,則到

資料庫中查詢;

三,Hibernate中的第一級快取

Hibernate的一級快取由Session提供,只存在於Session的生命週期中,當應用程式呼叫Session介面的save(),update(),saveOrupDate(),get(),load()或者Query和Criteria例項的list(),iterate()等方法時,如果Session快取中沒有相應的物件,hibernate就會把物件加入到一級快取中,當session關閉時,該Session所管理的一級快取也會立即被清除;

1,get查詢測試

1>在同一個session中發出兩次get查詢

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s1 = (Student)sess.get(Student.class2);  
  5.         System.out.println(s1.getName());  
  6.         Student s2 = (Student)sess.get(Student.class2);  
  7.         System.out.println(s2.getName());  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  
上面的兩次查詢,第一次執行了get方法查詢了資料庫,產生了一條sql語句,第二次執行get方法時,由於在一級快取中找到了該物件,因此不會查詢資料庫,不再發出sql語句;

2>開啟兩個session中發出兩次get查詢

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>        publicvoid Query(){  
  2.         Session sess1 = HibernateSessionFactory.getSession();  
  3.         Transaction tx1 = sess1.beginTransaction();  
  4.         Student s1 = (Student)sess1.get(Student.class2);  
  5.         System.out.println(s1.getName());  
  6.         tx1.commit();  
  7.         HibernateSessionFactory.closeSession();  
  8.         Session sess2 = HibernateSessionFactory.getSession();  
  9.         Transaction tx2 = sess2.beginTransaction();  
  10.         Student s2 = (Student)sess2.get(Student.class2);  
  11.         System.out.println(s2.getName());  
  12.         tx2.commit();  
  13.         HibernateSessionFactory.closeSession();  
  14.     }</strong></span>  
上面的兩次查詢,兩次執行get方法時都查詢了資料庫,產生了兩條sql語句,原因在於,第一次執行get方法查詢出結果後,關閉了session,快取被清除了,第二次執行get方法時,從快取中找不到結果,只能到資料庫查詢;

2,iterate查詢測試

插入一個iteritor查詢方式:

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Query query = sess.createQuery("from Student");  
  5.         Iterator iter = query.iterate();  
  6.         while(iter.hasNext()){  
  7.                System.out.println(((Student)iter.next()).getName());  
  8.         }  
  9.         tx.commit();  
  10.         HibernateSessionFactory.closeSession();  
  11.     }</strong></span>  
[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s1 = (Student)sess.createQuery("from Student s where s.id = 2").iterate().next();  
  5.         System.out.println(s1.getName());  
  6.         Student s2 = (Student)sess.createQuery("from Student s where s.id = 2").iterate().next();  
  7.         System.out.println(s2.getName());  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  
上面的程式碼執行後會生成三條sql語句,第一次執行iterate().next()時會發出查詢id的sql語句(第一條sql語句),得到s1物件,使用s1物件獲得name屬性值時會發出相應的查詢實體物件的sql語句(第二條sql語句),第二次執行iterate().next()時會發出查詢id的sql語句(第三條sql語句),但是不會發出查詢實體物件的sql語句,因為hibernate使用快取,不會發出sql語句

3,iterate查詢屬性測試:

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         String name1 = (String)sess.createQuery("select s.name from Student s where s.id = 2").iterate().next();  
  5.         System.out.println(name1);  
  6.         String name2 = (String)sess.createQuery("select s.name from Student s where s.id = 2").iterate().next();  
  7.         System.out.println(name2);  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  
上面的程式碼第一次執行iterate().next()時發出查詢屬性的sql語句,第二次執行iterate().next()時也會發出查詢屬性的sql語句,這是因為iterate查詢普通屬性,一級快取不會快取,所以會發出sql;

4,在一個session中先save,再執行load查詢

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s = new Student(8"newAcc"88);  
  5.         Serializable id = sess.save(s);  
  6.         tx.commit();  
  7.         Student s1 = (Student)sess.load(Student.class8);  
  8.         System.out.println(s1.getName());  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  
上面的程式碼執行save操作時,它會在快取裡放一份,執行load操作時,不會發出sql語句,因為save使用了快取;

--------------------

Session介面為應用程式提供了兩個管理快取的方法:

1>evict()方法:用於將某個物件從Session的一級快取中清除;

2>clear()方法:用於將一級快取中的所有物件全部清楚;

測試:

[java] view plain copy  print?
  1. <span style="font-size:18px;"><strong>  publicvoid Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s = (Student)sess.load(Student.class1);  
  5.         System.out.println(s.getName());  
  6.         sess.clear();//清除一級快取中的所有物件
  7.         Student s1 = (Student)sess.load(Student.class1);  
  8.         System.out.println(s1.getName());