Hibernate(七)---二級緩存

(一)Hibernate緩存概述
· 緩存(Cache): 計算機領域非常通用的概念。它介於應用程序和永久性數據存儲源(如硬盤上的文件或者數據庫)之間,其作用是降低應用程序直接讀寫永久性數據存儲源的頻率,從而提高應用的運行性能。緩存中的數據是數據存儲源中數據的拷貝。緩存的物理介質通常是內存。
· Hibernate中提供了兩個級別的緩存
第一級別的緩存是 Session 級別的緩存,它是屬於事務範圍的緩存。這一級別的緩存由 hibernate 管理的;
第二級別的緩存是 SessionFactory 級別的緩存,它是屬於進程範圍的緩存;
(二)SessionFactory級別的緩存

  • 內置緩存: Hibernate 自帶的, 不可卸載. 通常在 Hibernate 的初始化階段, Hibernate會把映射元數據和預定義的 SQL 語句放到 SessionFactory 的緩存中, 映射元數據是映射文件中數據(.hbm.xml 文件中的數據)的複製. 該內置緩存是隻讀的.
  • 外置緩存(二級緩存): 一個可配置的緩存插件. 在默認情況下, SessionFactory 不會啓用這個緩存插件. 外置緩存中的數據是數據庫數據的複製, 外置緩存的物理介質可以是內存或硬盤.
    (三)二級緩存
    (1)使用Hibernate的二級緩存

· 適合放入二級緩存中的數據:

  • 很少被修改
  • 不是很重要的數據, 允許出現偶爾的併發問題

· 不適合放入二級緩存中的數據:

  • 經常被修改
  • 財務數據, 絕對不允許出現併發問題
  • 與其他應用程序共享的數據
    (2)二級緩存的併發訪問策略
    · 兩個併發的事務同時訪問持久層的緩存的相同數據時, 也有可能出現各類併發問題.
    · 二級緩存可以設定以下 4 種類型的併發訪問策略, 每一種訪問策略對應一種事務隔離級別
  • 非嚴格讀寫(Nonstrict-read-write): 不保證緩存與數據庫中數據的一致性. 提供 Read Uncommited 事務隔離級別, 對於極少被修改, 而且允許髒讀的數據, 可以採用這種策略

  • 讀寫型(Read-write): 提供 Read Commited 數據隔離級別.對於經常讀但是很少被修改的數據, 可以採用這種隔離類型,因爲它可以防止髒讀

  • 事務型(Transactional): 僅在受管理環境下適用. 它提供了 Repeatable Read 事務隔離級別.對於經常讀但是很少被修改的數據, 可以採用這種隔離類型, 因爲它可以防止髒讀和不可重複讀

  • 只讀型(Read-Only):提供 Serializable 數據隔離級別, 對於從來不會被修改的數據, 可以採用這種訪問策略

(3)管理Hibernate的二級緩存
· Hibernate 的二級緩存是進程或集羣範圍內的緩存
· 二級緩存是可配置的的插件, Hibernate 允許選用以下類型的緩存插件:

  • EHCache: 可作爲進程範圍內的緩存, 存放數據的物理介質可以使內存或硬盤, 對 Hibernate 的查詢緩存提供了支持
  • OpenSymphony OSCache:可作爲進程範圍內的緩存, 存放數據的物理介質可以使內存或硬盤, 提供了豐富的緩存數據過期策略,對 Hibernate 的查詢緩存提供了支持

  • SwarmCache: 可作爲集羣範圍內的緩存, 但不支持 Hibernate 的查詢緩存

  • JBossCache:可作爲集羣範圍內的緩存, 支持 Hibernate 的查詢緩存
  • 4 種緩存插件支持的併發訪問策略(x 代表支持, 空白代表不支持)
    這裏寫圖片描述
    (4)配置進程範圍內的二級緩存的步驟

①選擇合適的緩存插件: EHCache(jar 包和 配置文件), 並編譯器配置文件
②在 Hibernate 的配置文件中啓用二級緩存並指定和 EHCache 對應的緩存適配器
③選擇需要使用二級緩存的持久化類, 設置它的二級緩存的併發訪問策略
- <class> 元素的 cache 子元素表明 Hibernate 會緩存對象的簡單屬性, 但不會緩存集合屬性, 若希望緩存集合屬性中的元素, 必須在 <set> 元素中加入 <cache> 子元素
- 在 hibernate 配置文件中通過 <class-cache/> 節點配置使用緩存

       <!-- 啓用二級緩存 -->
        <property name="cache.use_second_level_cache">true</property>

        <!-- 配置使用的二級緩存的產品 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

(5)ehcache.xml
· <diskStore>: 指定一個目錄:當 EHCache 把數據寫到硬盤上時, 將把數據寫到這個目錄下.
· <defaultCache>: 設置緩存的默認數據過期策略
· <cache> 設定具體的命名緩存的數據過期策略。每個命名緩存代表一個緩存區域
· 緩存區域(region):一個具有名稱的緩存塊,可以給每一個緩存塊設置不同的緩存策略。如果沒有設置任何的緩存區域,則所有被緩存的對象,都將使用默認的緩存策略。即:<defaultCache.../>
· Hibernate在不同的緩存區域保存不同的類/集合。
- 對於類而言,區域的名稱是類名。如:com.ty.domain.Customer
- 對於集合而言,區域的名稱是類名加屬性名。如com.ty.domain.Customer.orders
· cache 元素的屬性

* name:設置緩存的名字,它的取值爲類的全限定名或類的集合的名字 
* maxInMemory:設置基於內存的緩存中可存放的對象最大數目 
* eternal:設置對象是否爲永久的,true表示永不過期,此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 默認值是false 
* timeToIdleSeconds:設置對象空閒最長時間,以秒爲單位, 超過這個時間,對象過期。當對象過期時,EHCache會把它從緩存中清除。如果此值爲0,表示對象可以無限期地處於空閒狀態。 
* timeToLiveSeconds:設置對象生存最長時間,超過這個時間,對象過期。如果此值爲0,表示對象可以無限期地存在於緩存中. 該屬性值必須大於或等於 timeToIdleSeconds 屬性值 
* overflowToDisk:設置基於內存的緩存中的對象數目達到上限後,是否把溢出的對象寫到基於硬盤的緩存中 

<ehcache>


    <!--  
        指定一個目錄:當 EHCache 把數據寫到硬盤上時, 將把數據寫到這個目錄下.
    -->     
    <diskStore path="d:\\tempDirectory"/>



    <!--  
        設置緩存的默認數據過期策略 
    -->    
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    //類的緩存區域
    <cache name="com.atguigu.hibernate.entities.Employee"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
      //集合的緩存區域
    <cache name="com.atguigu.hibernate.entities.Department.emps"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        />

</ehcache>

(四)查詢緩存
· 對於經常使用的查詢語句, 如果啓用了查詢緩存, 當第一次執行查詢語句時, Hibernate 會把查詢結果存放在查詢緩存中. 以後再次執行該查詢語句時, 只需從緩存中獲得查詢結果, 從而提高查詢性能
· 查詢緩存使用於如下場合:

  • 應用程序運行時經常使用查詢語句
  • 很少對與查詢語句檢索到的數據進行插入, 刪除和更新操作

· 啓用查詢緩存的步驟

  • ①配置二級緩存, 因爲查詢緩存依賴於二級緩存
  • ②在 hibernate 配置文件中啓用查詢緩存
  • ③對於希望啓用查詢緩存的查詢語句, 調用 Query 或Criteria的 setCacheable() 方法
@Test
    public void testQuerySession(){
    /*
        String hql = "From Employee";
        Query query = session.createQuery(hql);
        query.setCacheable(true);
        List<Employee> emps = query.list();
        System.out.println(emps.size());
        /*
        emps = query.list();
        System.out.println(emps.size());
        */
        Criteria criteria = session.createCriteria(Employee.class);
        criteria.setCacheable(true);
        List<Employee> emps = criteria.list();
        System.out.println(emps.size());

         emps = criteria.list();
        System.out.println(emps.size());
    }

(五)時間戳緩存區域

時間戳緩存區域存放了對於查詢結果相關的表進行插入, 更新或刪除操作的時間戳. Hibernate 通過時間戳緩存區域來判斷被緩存的查詢結果是否過期, 其運行過程如下:

  • T1 時刻執行查詢操作, 把查詢結果存放在 QueryCache 區域, 記錄該區域的時間戳爲 T1

  • T2 時刻對查詢結果相關的表進行更新操作, Hibernate 把 T2 時刻存放在 UpdateTimestampCache 區域.

  • T3 時刻執行查詢結果前, 先比較 QueryCache 區域的時間戳和 UpdateTimestampCache 區域的時間戳, 若T2 >T1, 那麼就丟棄原先存放在 QueryCache 區域的查詢結果, 重新到數據庫中查詢數據, 再把結果存放到 QueryCache 區域; 若 T2 < T1, 直接從 QueryCache 中獲得查詢結果

(六)Query 接口的 iterate() 方法

  • Query 接口的 iterator() 方法同 list() 一樣也能執行查詢操作;

  • list() 方法執行的 SQL 語句包含實體類對應的數據表的所有字段;

  • Iterator() 方法執行的SQL 語句中僅包含實體類對應的數據表的 ID 字段

  • 當遍歷訪問結果集時, 該方法先到 Session 緩存及二級緩存中查看是否存在特定 OID 的對象, 如果存在, 就直接返回該對象,
    如果不存在該對象就通過相應的 SQL Select 語句到數據庫中加載特定的實體對象

  • 大多數情況下, 應考慮使用 list() 方法執行查詢操作. iterator() 方法僅在滿足以下條件的場合, 可以稍微提高查詢性能:①要查詢的數據表中包含大量字段;②啓用了二級緩存, 且二級緩存中可能已經包含了待查詢的對象

    @Test
    public void testQueryIterator(){
        Deparment dept = (Deparment)session.get(Deparment.class, 2);
        System.out.println(dept.getName());
        System.out.println(dept.getEmps().size());

        String hql = "From Employee e where e.dept = 1";
        Query query = session.createQuery(hql);
        /*
        List<Employee> emp = query.list();
        System.out.println(emp.size());
        */
        Iterator<Employee> iterator = query.iterate();
        while(iterator.hasNext()){
            System.out.println(iterator.next().getName());
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章