Hibernate 緩存機制淺析

1. 爲何要用 Hibernate 緩存?

   Hibernate是一個持久層框架,常常訪問物理數據庫。java

   爲了下降應用程序對物理數據源訪問的頻次,從而提升應用程序的運行性能。git

   緩存內的數據是對物理數據源中的數據的複製,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。sql

2. 項目實戰

   當 Session 對象調用 save() 方法保存一個對象後,該對象會被放入到 Session 緩存中。數據庫

   當 Session 對象調用 get() 或 load() 方法從數據庫取出一個對象後,該對象也會被放入到 Session 緩存中。 緩存

   當使用同一個 Session 編寫 HQL 和 QBC 等從數據庫中查詢數據時,將直接從緩存中讀取數據,不會訪問數據庫。session

   Hibernate 提供了幾個方法(evit/clear/contains/flush....)來管理和判斷一級緩存。併發

   現 JavaEE Dao 層中,提供給外部的數據庫訪問,每次都會從 Session 工廠中獲取新的 Session 線程 ,致使一級緩存不多被利用。框架

   實例項目源碼:https://git.oschina.net/LanboEx/hiberdemoide

        //1.Hibernate 自身的一級緩存,能夠查看到只輸出了一條 sql
        Session session = getSession(); UserPO userPO = session.get(UserPO.class, "031e7a36972e11e6acede16e8241c0fe"); System.out.println("1. 第一次訪問 DB:" + userPO.getName() + "," + userPO.getPasswd()); UserPO userPO1 = session.get(UserPO.class, "031e7a36972e11e6acede16e8241c0fe"); System.out.println("2. 第二次訪問 DB:" + userPO1.getName() + ",一級緩存中是否存在特定對象" + session.contains(userPO));

       //2.使用 evite/clear 方法手動清除緩存中特定對象,能夠看到 hiber 輸出了兩條 SQL
        Session session1 = getSession(); UserPO userPO3 = session1.get(UserPO.class, "031e7a36972e11e6acede16e8241c0fe"); System.out.println("3. 第一次獲取對象:" + userPO3.getName() + "," + userPO3.getPasswd()); session1.evict(userPO3); UserPO userPO4 = session1.get(UserPO.class, "031e7a36972e11e6acede16e8241c0fe"); System.out.println("4. 第二次獲取對象:" + userPO4.getName() + "," + userPO4.getPasswd());

3. Hibernate 緩存原理

   Hibernate 緩存包括兩大類:性能

a.Hibernate 一級緩存,又稱爲[Session的緩存]。

   Session 內置不能被卸載,Session 的緩存是事務範圍的緩存(Session 對象的生命週期一般對應一個數據庫事務或者一個應用事務)。

   一級緩存中,持久化類的每一個實例都具備惟一的 OID。

b.Hibernate 二級緩存,又稱爲[SessionFactory的緩存]。

   因爲 SessionFactory 對象的生命週期和應用程序的整個過程對應。

   Hibernate二級緩存是進程範圍或者集羣範圍的緩存,有可能出現併發問題,須要採用適當的併發訪問策略,該策略爲被緩存的數據提供了事務隔離級別。

   第二級緩存是可選的,是一個可配置的插件,默認下 SessionFactory 不會啓用這個插件。

   Hibernate 提供了 org.hibernate.cache.CacheProvider 接口,它充當緩存插件與 Hibernate 之間的適配器。

   什麼樣的數據適合存放到第二級緩存中?

   1) 不多被修改的數據

   2) 不是很重要的數據,容許出現偶爾併發的數據

   3) 不會被併發訪問的數據

   4) 常量數據

不適合存放到第二級緩存的數據?

  1) 常常被修改的數據

  2) 絕對不容許出現併發訪問的數據,如財務數據,絕對不容許出現併發 

  3) 與其餘應用共享的數據。

c.Session 的延遲加載實現要解決兩個問題:正常關閉鏈接和確保請求中訪問的是同一個 Session。

   Hibernate Session 就是 java.sql.Connection 的一層高級封裝,一個 Session 對應了一個 Connection。

   Http 請求結束後正確的關閉 Session(過濾器實現了Session的正常關閉);

   延遲加載必須保證是同一個 Session( Session 綁定在 ThreadLocal)。

d.Hibernate 查找對象如何應用緩存?

   當 Hibernate 根據 ID 訪問數據對象的時候,首先從 Session 一級緩存中查;

   查不到,若是配置了二級緩存,那麼從二級緩存中查;

   若是都查不到,再查詢數據庫,把結果按照 ID 放入到緩存刪除、更新、增長數據的時候,同時更新緩存。

e.一級緩存與二級緩存的對比圖

 

一級緩存

二級緩存

存放數據的形式

相互關聯的持久化對象

對象的散裝數據

緩存的範圍

事務範圍,每一個事務都擁有單獨的一級緩存

進程範圍或集羣範圍,緩存被同一個進程或集羣範圍內全部事務共享

併發訪問策略

因爲每一個事務都擁有單獨的一級緩存不會出現併發問題,所以無須提供併發訪問策略

因爲多個事務會同時訪問二級緩存中的相同數據,所以必須提供適當的併發訪問策略,來保證特定的事務隔離級別

數據過時策略

處於一級緩存中的對象永遠不會過時,除非應用程序顯示清空或者清空特定對象

必須提供數據過時策略,如基於內存的緩存中對象的最大數目,容許對象處於緩存中的最長時間,以及容許對象處於緩存中的最長空閒時間

物理介質

內存

內存和硬盤,對象的散裝數據首先存放到基於內存的緩存中,當內存中對象的數目達到數據過時策略的maxElementsInMemory值,就會把其他的對象寫入基於硬盤的緩存中

緩存軟件實現

在Hibernate的Session的實現中包含

由第三方提供,Hibernate僅提供了緩存適配器,用於把特定的緩存插件集成到Hibernate中

啓用緩存的方式

只要經過Session接口來執行保存,更新,刪除,加載,查詢,Hibernate就會啓用一級緩存,對於批量操做,如不但願啓用一級緩存,直接經過JDBCAPI來執行

用戶能夠再單個類或類的單個集合的粒度上配置第二級緩存,若是類的實例被常常讀,但不多被修改,就能夠考慮使用二級緩存,只有爲某個類或集合配置了二級緩存,Hibernate在運行時纔會把它的實例加入到二級緩存中

用戶管理緩存的方式

一級緩存的物理介質爲內存,因爲內存的容量有限,必須經過恰當的檢索策略和檢索方式來限制加載對象的數目,Session的evit()方法能夠顯示的清空緩存中特定對象,但不推薦

二級緩存的物理介質可使內存和硬盤,所以第二級緩存能夠存放大容量的數據,數據過時策略的maxElementsInMemory屬性能夠控制內存中的對象數目,管理二級緩存主要包括兩個方面:選擇須要使用第二級緩存的持久化類,設置合適的併發訪問策略;選擇緩存適配器,設置合適的數據過時策略。SessionFactory的evit()方法也能夠顯示的清空緩存中特定對象,但不推薦

相關文章
相關標籤/搜索