Hibernate中一級快取和二級快取使用詳解

徐劉根的專欄發表於2014-10-14

一、一級快取二級快取的概念解釋

(1)一級快取就是Session級別的快取,一個Session做了一個查詢操作,它會把這個操作的結果放在一級快取中,如果短時間內這個

session(一定要同一個session)又做了同一個操作,那麼hibernate直接從一級快取中拿,而不會再去連資料庫,取資料;

(2)二級快取就是SessionFactory級別的快取,顧名思義,就是查詢的時候會把查詢結果快取到二級快取中,如果同一個sessionFactory

建立的某個session執行了相同的操作,hibernate就會從二級快取中拿結果,而不會再去連線資料庫;

(3)Hibernate中提供了兩級Cache,第一級別的快取是Session級別的快取,它是屬於事務範圍的快取。這一級別的快取由hibernate管理

的,一般情況下無需進行干預;第二級別的快取是SessionFactory級別的快取,它是屬於程式範圍或群集範圍的快取。這一級別的緩

存可以進行配置和更改,並且可以動態載入和解除安裝。 Hibernate還為查詢結果提供了一個查詢快取,它依賴於第二級快取;

二、一級快取和二級快取的比較

(1)第一級快取 第二級快取 存放資料的形式相互關聯的持久化物件 物件的散裝資料 快取的範圍事務範圍,每個事務都有單獨的第一級

快取程式範圍或叢集範圍,快取被同一個程式或叢集範圍內的所有事務共享併發訪問策略由於每個事務都擁有單獨的第一級快取,不

會出現併發問題,無需提供併發訪問策略由於多個事務會同時訪問第二級快取中相同資料,因此必須提供適當的併發訪問策略,來保

證特定的事務隔離級別資料過期策略沒有提供資料過期策略。

(2)處於一級快取中的物件永遠不會過期,除非應用程式顯式清空快取或者

清除特定的物件必須提供資料過期策略,如基於記憶體的快取中的物件的最大數目,允許物件處於快取中的最長時間,以及允許物件處

於快取中的最長空閒時間物理儲存介質記憶體記憶體和硬碟。

(3)物件的散裝資料首先存放在基於記憶體的快取中,當記憶體中物件的數目達到數

據過期策略中指定上限時,就會把其餘的物件寫入基於硬碟的快取中。

(4)快取的軟體實現在Hibernate的Session的實現中包含了快取的

實現由第三方提供,Hibernate僅提供了快取介面卡(CacheProvider)。用於把特定的快取外掛整合到Hibernate中。

(5)啟用快取的方式

只要應用程式通過Session介面來執行儲存、更新、刪除、載入和查詢資料庫資料的操作,Hibernate就會啟用第一級快取,把資料庫

中的資料以物件的形式拷貝到快取中,對於批量更新和批量刪除操作,如果不希望啟用第一級快取,可以繞過Hibernate API,直接

通過JDBC API來執行指操作。

(6)使用者可以在單個類或類的單個集合的粒度上配置第二級快取。如果類的例項被經常讀但很少被修改,就

可以考慮使用第二級快取。

(7)只有為某個類或集合配置了第二級快取,Hibernate在執行時才會把它的例項加入到第二級快取中。

使用者管理快取的方式第一級快取的物理介質為記憶體,由於記憶體容量有限,必須通過恰當的檢索策略和檢索方式來限制載入物件的數目。

Session的 evit()方法可以顯式清空快取中特定物件,但這種方法不值得推薦。第二級快取的物理介質可以是記憶體和硬碟,因此第二

級快取可以存放大量的資料,資料過期策略的maxElementsInMemory屬性值可以控制記憶體中的物件數目。

(8)管理第二級快取主要包括兩個方面:選擇需要使用第二級快取的持久類,設定合適的併發訪問策略:選擇快取介面卡,設定合適的資料過期策略。

三、 一級快取的管理

(1)當應用程式呼叫Session的save()、update()、savaeOrUpdate()、get()或load(),以及呼叫查詢介面的 list()、iterate()或

filter()方法時,如果在Session快取中還不存在相應的物件,Hibernate就會把該物件加入到第一級快取中。當清理快取時,

Hibernate會根據快取中物件的狀態變化來同步更新資料庫。 Session為應用程式提供了兩個管理快取的方法: evict(Object obj)

:從快取中清除引數指定的持久化物件。 clear():清空快取中所有持久化物件。

(2)save、update、saveOrupdate、load、list、iterate、lock會向一級快取存放資料;

save 案例:
	//新增一個學生
			Student student=new Student();
			student.setName("小東");

			s.save(student);//放入一級快取

			//我馬上查詢
			Student stu2=(Student) s.get(Student.class, student.getId()); //select
			System.out.println("你剛剛加入的學生名字是"+stu2.getName());

(3)什麼操作會從一級快取取資料:get、load、list

get / load 會首先從一級快取中取,如沒有.再有不同的操作[get 會立即向資料庫發請求,而load 會返回一個代理物件,直到使用者真的去使用資料,才會向資料庫發請求;

//查詢45號學生

			Student stu=(Student) s.get(Student.class, 45);

			System.out.println("|||||||||||||||||||");

			String hql="from Student where id=45";

			Student stu2=(Student) s.createQuery(hql).uniqueResult();

			System.out.println(stu2.getName());

從上面的案例,我們看出 query.list() query.uniueResut() 不會從一級緩取資料! 但是query.list 或者query.uniqueRestu() 會向一級快取放資料的.

注意:

① 一級快取不需要配置,就可以使用,它本身沒有保護機制,所以我們程式設計師要考慮這個問題,我們可以同 evict 或者 clear來清除session快取中物件. evict 是清除一個物件,clear是清除所有的sesion快取物件

② session級快取中物件的生命週期, 當session關閉後,就自動銷燬.

③ 我們自己用HashMap來模擬一個Session快取,加深對快取的深入.

四、Hibernate二級快取的管理

1. Hibernate二級快取策略的一般過程如下:

1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有欄位)這樣的SQL語句查詢資料庫,一次獲得所有的資料物件。

2) 把獲得的所有資料物件根據ID放入到第二級快取中。

3) 當Hibernate根據ID訪問資料物件的時候,首先從Session一級快取中查;查不到,如果配置了二級快取,那麼從二級快取中查;查不到,再查詢資料庫,把結果按照ID放入到快取。

4) 刪除、更新、增加資料的時候,同時更新快取。

Hibernate二級快取策略,是針對於ID查詢的快取策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache。

5) 二級快取的物件可能放在記憶體,也可能放在磁碟.

2. 什麼樣的資料適合存放到第二級快取中?

1) 很少被修改的資料

2) 不是很重要的資料,允許出現偶爾併發的資料

3) 不會被併發訪問的資料

4) 參考資料,指的是供應用參考的常量資料,它的例項數目有限,它的例項會被許多其他類的例項引用,例項極少或者從來不會被修改。

3. 不適合存放到第二級快取的資料?

1) 經常被修改的資料

2) 財務資料,絕對不允許出現併發

3) 與其他應用共享的資料。

4. 常用的快取外掛 Hibernater二級快取是一個外掛,下面是幾種常用的快取外掛:

Ehcache:可作為程式範圍的快取,存放資料的物理介質可以是記憶體或硬碟,對Hibernate的查詢快取提供了支援。

◆OSCache:可作為程式範圍的快取,存放資料的物理介質可以是記憶體或硬碟,提供了豐富的快取資料過期策略,對Hibernate的查詢

快取提供了支援。

◆SwarmCache:可作為群集範圍內的快取,但不支援Hibernate的查詢快取。

◆JBossCache:可作為群集範圍內的快取,支援事務型併發訪問策略,對Hibernate的查詢快取提供了支援。

5. 配置Hibernate二級快取的主要步驟:

1) 選擇需要使用二級快取的持久化類,設定它的命名快取的併發訪問策略。這是最值得認真考慮的步驟。

2) 選擇合適的快取外掛,然後編輯該外掛的配置檔案。

<property name="hbm2ddl.auto">update</property>
	<!-- 啟動二級快取 -->
	<property name="cache.use_second_level_cache">true</property>
	<!-- 指定使用哪種二級快取 -->
	<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
	<mapping resource="com/hsp/domain/Department.hbm.xml" />
	<mapping resource="com/hsp/domain/Student.hbm.xml" />
	<!-- 指定哪個domain啟用二級快取 
	特別說明二級快取策略:
	1. read-only
	2. read-write
	3. nonstrict-read-write
	4. transcational
	-->
	<class-cache usage="read-write"/>

3)可以把oscache.properties檔案放在 src目錄下,這樣你可以指定放入二級快取的物件capacity 大小. 預設1000

6.使用二級快取:

// TODO Auto-generated method stub
		//通過獲取一個sesion,讓hibernate框架執行(config->載入hibernate.cfg.xml)
		Session s=null;
		Transaction tx=null;

		try {
			//我們使用基礎模板來講解.
			s=HibernateUtil.openSession();
			tx=s.beginTransaction();

			//查詢45號學生

			Student stu1=(Student) s.get(Student.class, 45);//45->一級快取		
			System.out.println(stu1.getName());

			tx.commit();

		} catch (Exception e) {
			e.printStackTrace();
			if(tx!=null){
				tx.rollback();
			}
		}finally{

			if(s!=null && s.isOpen()){
				s.close();
			}
		}

		System.out.println("*********************************");
		try {
			//我們使用基礎模板來講解.
			s=HibernateUtil.openSession();
			tx=s.beginTransaction();

			//查詢45號學生

			Student stu1=(Student) s.get(Student.class, 45);	
			System.out.println(stu1.getName());

			Student stu3=(Student) s.get(Student.class, 46);	
			System.out.println(stu3.getName());
				tx.commit();

		} catch (Exception e) {
			e.printStackTrace();
			if(tx!=null){
				tx.rollback();
			}
		}finally{

			if(s!=null && s.isOpen()){
				s.close();
			}
		}

		//完成一個統計,統計的資訊在Sessfactory
		//SessionFactory物件.
		Statistics statistics= HibernateUtil.getSessionFactory().getStatistics();
		System.out.println(statistics);
		System.out.println("放入"+statistics.getSecondLevelCachePutCount());
		System.out.println("命中"+statistics.getSecondLevelCacheHitCount());
		System.out.println("錯過"+statistics.getSecondLevelCacheMissCount());

在配置了二級快取後,請大家要注意可以通過 Statistics,檢視你的配置命中率高不高

相關文章