hibernate 的緩存機制


  Hibernate的緩存包括Session的緩存和SessionFactory的緩存,其中SessionFactory的緩存又可以分為兩類:

    • 內置緩存

  SessionFactory的內置緩存和Session的緩存在實現方式上比較相似,前者是SessionFactory對象的一些集合屬性包含的數據,后者是指Session的一些集合屬性包含的數據。SessionFactory的內置緩存中存放了映射元數據和預定義SQL語句,映射元數據是映射文件中數據的拷貝,而預定義SQL語句是在Hibernate初始化階段根據映射元數據推導出來,SessionFactory的內置緩存是只讀的,應用程序不能修改緩存中的映射元數據和預定義SQL語句,因此SessionFactory不需要進行內置緩存與映射文件的同步。

    • 外置緩存

      SessionFactory的外置緩存是一個可配置的插件。默認情況下並未啟動。外置緩存的介質可以是內存或者硬盤。

一級緩存:

  一級緩存即session級別的緩存,亦即事務級別的緩存策略,這種緩存策略是Hibernate內置的,不可被拆卸的。

二級緩存:

  Hibernate的第二級緩存即SessionFactory的外置緩存,其同時也稱為進程級緩存或集群范圍內的緩存。hibernate的二級緩存是需要第三方支持的,hibernate默認的二級緩存插件為ehcache,由於二級緩存是進程級的可能出現多線程並發問題,需要設置緩存的並發策略。

  那什么樣的數據時可以放到二級緩存中的呢,如下所示:

    • 修改頻率低的數據;
    • 不是很重要的數據,允許偶爾出現並發的數據;
    • 不會被並發訪問的數據;
    • 參考性的數據,只是展示或者用於其他方面;

  那么不適合存放到二級緩存中的數據就有:

    • 經常被修改的數據;
    • 絕對不允許出現並發的數據,比如財務型的數據;
    • 與其他應用共享的數據;

  我們可以通過配置hibernate的屬性"hibernate.cache.region.factory_class"(hibernate4之后改用這個屬性名來配置cacheProvider)來配置緩存的提供者CacheProvider。

  下面是不同cache車間的cacheProvider的提供者的說明

Cache(緩存插件名稱) Provider Class(cacheProvider提供者) Type(支持緩存類型) Cluster Safe(集群安全) Query Cache Supported(是否支持查詢緩存)
ConcurrentHashMap (only for testing purpose, in hibernate-testing module)(僅用於測試) org.hibernate.testing.cache.CachingRegionFactory
memory
  yes
EHCache org.hibernate.cache.ehcache.EhCacheRegionFactory memory, disk, transactional, clustered yes yes
Infinispan org.hibernate.cache.infinispan.InfinispanRegionFactory clustered (ip multicast), transactional yes (replication or invalidation) yes (clock sync req.)

  默認情況下,entity對象並沒有別緩存到二級緩存中,但是如何你不想這樣做的話,你可以在配置文件中設置屬性 "javax.persistence.sharedCache.mode" 的值來覆蓋這個設置,可以設置的值有以下幾個值:

    • ENABLE_SELECTIVE (默認推薦的值): 所有的entity不被緩存,除非明確被標注為可被緩存。
    • DISABLE_SELECTIVE: 所有的entity被緩存,除非明確被標注為不可緩存。
    • ALL: 所有的entity被緩存,即使被標注為不可緩存。
    • NONE: 所有的entity不被緩存,即使被標注為不可緩存。這個選項只有在不啟動二級緩存的情況下才有意義。

  我們可以通過在配置文件中通過設置屬性 "hibernate.cache.default_cache_concurrency_strategy" 的值來設置全局的緩存策略,但是不推薦這樣做,一般情況下我們通過注解 @org.hibernate.annotations.Cache 來根據情況設置不同的緩存策略。就像下面的設置:

//Definition of cache concurrency strategy via @Cache
@Entity
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Classroom implements Serializable{...}


//Caching collections using annotations
@OneToMany(mappedBy="school", cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public Set<Classroom> getClassrooms() {
    return classrooms;
}

   下面我們來看一下hibernate為我們提供的四種不同的緩存策略:

  • read-only

    如果你的應用數據只是需要讀而不需要更改,那么對於這個持久化的實例就可以使用這個緩存策略,這個緩存策略是最簡單也是最好用的一種策略,即使在集群環境中也是很安全的。

  • read-write

    如果應用數據需要更改,那么這種策略是合適的。這種緩存策略不適合那種要求有嚴格的事務隔離級別的應用環境。如果現在你的應用的緩存是需要用在JTA的環境中的話,那么我們就必須配置屬性"hibernate.transaction.manager_lookup_class"指向一個JTA TransactionManager。在其他的環境中,如果使用這個策略的話,要確保事務在調用完Session.close()或者是Session.disconnect()之后結束。如果你想在集群環境中使用這種緩存策略的話,那么我們引入的第三方緩存插件需要支持鎖機制。hibernate內置的cache providers是不支持鎖機制的。

  • nonstrict-read-write

    如果應用系統只是偶爾的更新數據(這種情況下就極不可能會出現兩個事物同時試着來更新相同的數據),並且並不要求嚴格的事物隔離級別的話,那么這個緩存策略是合適的。如果現在你的應用的緩存是需要用在JTA的環境中的話,那么我們就必須配置屬性"hibernate.transaction.manager_lookup_class"的值啦。在其他的環境中,如果使用這個策略的話,要確保事務在調用完Session.close()或者是Session.disconnect()之后結束。

  • transactional

    這個緩存策略提供對全事務緩存機制的支持,比如JBoss TreeCache。它只能被使用在JTA的環境中,而且還必須指定屬性"hibernate.transaction.manager_lookup_class"的值。

 

   以下我們來看一下常用的緩存插件對以上緩存策略的支持程度如何:

Cache(緩存插件名稱) read-only nonstrict-read-write read-write transactional
ConcurrentHashMap (僅測試時使用) yes yes yes  
EHCache yes yes yes yes
Infinispan yes     yes

 查詢緩存(The Query Cache):

  被查詢的集合也可以被緩存,但是這只適用於下次查詢時還是使用相同的查詢參數。你可以通過設置屬性"hibernate.cache.use_query_cache"的值為true來啟動查詢緩存。

  你也可以通過調用方法來手動設置查詢緩存,代碼如下所示:

org.hibernate.Query.setCacheable(true);

 

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

以上是參考了網上的一些數據以及Hibernate的英文資料整理出來的,如果有什么欠缺的地方,還請大家能指出來。我們來一起討論討論。共同進步嗎。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM