理解緩存的定義:
緩存(Cache): 計算機領域非常通用的概念。它介於應用程序和永久性數據存儲源(如硬盤上的文件或者數據庫)之間,其作用是降低應用程序直接讀寫永久性數據存儲源的頻率,從而提高應用的運行性能。緩存中的數據是數據存儲源中數據的拷貝。緩存的物理介質通常是內存。
理解二級緩存的定義:
Hibernate中提供了兩個級別的緩存
-
- 第一級別的緩存是 Session 級別的緩存,它是屬於事務范圍的緩存。這一級別的緩存由 hibernate 管理的,一般情況下無需進行干預
- 第二級別的緩存是 SessionFactory 級別的緩存,它是屬於進程范圍的緩存
SessionFactory 的緩存可以分為兩類:
-
- 內置緩存: Hibernate 自帶的, 不可卸載. 通常在 Hibernate 的初始化階段, Hibernate 會把映射元數據和預定義的 SQL 語句放到 SessionFactory 的緩存中, 映射元數據是映射文件中數據的復制, 而預定義 SQL 語句是 Hibernate 根據映射元數據推到出來的. 該內置緩存是只讀的.
- 外置緩存(二級緩存): 一個可配置的緩存插件. 在默認情況下, SessionFactory 不會啟用這個緩存插件. 外置緩存中的數據是數據庫數據的復制, 外置緩存的物理介質可以是內存或硬盤
理解二級緩存的並發訪問策略
- 兩個並發的事務同時訪問持久層的緩存的相同數據時, 也有可能出現各類並發問題.
- 二級緩存可以設定以下 4 種類型的並發訪問策略, 每一種訪問策略對應一種事務隔離級別
-
- 非嚴格讀寫(Nonstrict-read-write): 不保證緩存與數據庫中數據的一致性. 提供 Read Uncommited 事務隔離級別, 對於極少被修改, 而且允許臟讀的數據, 可以采用這種策略
- 讀寫型(Read-write): 提供 Read Commited 數據隔離級別.對於經常讀但是很少被修改的數據, 可以采用這種隔離類型, 因為它可以防止臟讀
- 事務型(Transactional): 僅在受管理環境下適用. 它提供了 Repeatable Read 事務隔離級別. 對於經常讀但是很少被修改的數據, 可以采用這種隔離類型, 因為它可以防止臟讀和不可重復讀
- 只讀型(Read-Only):提供 Serializable 數據隔離級別, 對於從來不會被修改的數據, 可以采用這種訪問策略(很強,但是性能低)
緩存中存放的數據
- 適合放入二級緩存中的數據:
-
- 很少被修改
- 不是很重要的數據, 允許出現偶爾的並發問題
- 不適合放入二級緩存中的數據:
-
- 經常被修改
- 財務數據, 絕對不允許出現並發問題
- 與其他應用數據共享的數據
緩存提供的供應商
- Hibernate 的二級緩存是進程或集群范圍內的緩存, 緩存中存放的是對象的散裝數據
- 二級緩存是可配置的的插件, Hibernate 允許選用以下類型的緩存插件:
-
- EHCache: 可作為進程范圍內的緩存, 存放數據的物理介質可以是內存或硬盤, 對 Hibernate 的查詢緩存提供了支持
- OpenSymphony OSCache:可作為進程范圍內的緩存, 存放數據的物理介質可以使內存或硬盤, 提供了豐富的緩存數據過期策略, 對 Hibernate 的查詢緩存提供了支持
- SwarmCache: 可作為集群范圍內的緩存, 但不支持 Hibernate 的查詢緩存
- JBossCache:可作為集群范圍內的緩存, 支持 Hibernate 的查詢緩存
- 4 種緩存插件支持的並發訪問策略(x 代表支持, 空白代表不支持)
項目中的配置 (配置進程范圍內的二級緩存【配置ehcache緩存】)
(1) 需要引入三個jar包
- 在hibernate下能找到hibernate-distribution-3.6.10-Final\lib\optional\ehcache\ehcache-1.5.0.jar
- 在srping下能找到
..\lib\concurrent\backport-util-concurrent.jar
..\lib\jakarta-commons\commons-logging.jar
- 拷貝到當前工程的lib目錄下
(2) 開啟二級緩存
<property name="hibernate.cache.use_second_level_cache">true</property>
(3) 要指定緩存的供應商
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
(4) 指定使用二級緩存的類
* 方法一 在使用類的*.hbm.xml配置
- 選擇需要使用二級緩存的持久化類, 設置它的二級緩存的並發訪問策略,<class> 元素的 cache 子元素表明 Hibernate 會緩存對象的簡單屬性, 但不會緩存集合屬性, 若希望緩存集合屬性中的元素, 必須在 <set> 元素中加入 <cache> 子元素
-
1 <class name="cn.fuyi.xxx.entity.Person" table="persons" lazy="false"> 2 <!-- 配置類級別的二級緩存 --> 3 <cache usage="read-write"/> 4 </class> 5 6 <set name="orders" table="orders" inverse="true" fetch="select" lazy="false"> 7 <!-- 配置集合級別的二級緩存 --> 8 <cache usage="read-write"/> 9 </set>
* 方法二 在hibernate.cfg.xml文件中配置(建議)
1 <!-- 指定使用二級緩存的類 放在mapping下面 --> 2 3 <!-- 配置類級別的二級緩存 --> 4 <class-cache class="cn.itcast.c3p0.Customer" usage="read-write"/> 5 <class-cache class="cn.itcast.c3p0.Order" usage="read-write"/> 6 7 <!-- 配置集合級別的二級緩存 --> 8 <collection-cache collection="cn.itcast.c3p0.Customer.orders" 9 usage="read-write"/>
(5) 配置ehcache默認的配置文件ehcache.xml(名字固定)(放在類路徑下)
1 ehcache.xml文件 2 3 <diskStore path="D:\cache" /> 4 <cache name=" “ 5 maxElementsInMemory="100“ 6 eternal="false" 7 timeToIdleSeconds="300“ 8 timeToLiveSeconds="600" 9 overflowToDisk="true“ 10 diskPersistent="false“ /> 11 </ehcache>
配置ehcache緩存的說明:
- <diskStore>:指定一個目錄, 當 EHCache 把數據寫到硬盤上時, 將把數據寫到這個文件目錄下. 默認是C:\WINDOWS\Temp
- <defaultCache>: 設置緩存的默認數據過期策略
- <cache> 設定具體的命名緩存的數據過期策略
- 每個命名緩存代表一個緩存區域,每個緩存區域有各自的數據過期策略。命名緩存機制使得用戶能夠在每個類以及類的每個集合的粒度上設置數據過期策略。
- cache元素的屬性
- name:設置緩存的名字,它的取值為類的全限定名或類的集合的名字
- maxElementsInMemory :設置基於內存的緩存中可存放的對象最大數目
- eternal:設置對象是否為永久的,true表示永不過期,此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 默認值是false
- timeToIdleSeconds:設置對象空閑最長時間,以秒為單位, 超過這個時間,對象過期。當對象過期時,EHCache會把它從緩存中清除。如果此值為0,表示對象可以無限期地處於空閑狀態。
- timeToLiveSeconds:設置對象生存最長時間,超過這個時間,對象過期。
如果此值為0,表示對象可以無限期地存在於緩存中. 該屬性值必須大於或等於 timeToIdleSeconds 屬性值 - overflowToDisk:設置基於內在的緩存中的對象數目達到上限后,是否把溢出的對象寫到基於硬盤的緩存中
- diskPersistent 當jvm結束時是否持久化對象 true false 默認是false
- diskExpiryThreadIntervalSeconds 指定專門用於清除過期對象的監聽線程的輪詢時間
- 以下屬性是必須的:
- maxElementsInMemory - 在內存中緩存的element的最大數目
- maxElementsOnDisk - 在磁盤上緩存的element的最大數目
- eternal - 設定緩存的elements是否永遠不過期。如果為true,則緩存的數據始終有效,如果為false那么還要根據timeToIdleSeconds,timeToLiveSeconds判斷
- overflowToDisk - 設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上
- 以下屬性是可選的:
- timeToIdleSeconds - 當緩存在EhCache中的數據前后兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除.
- timeToLiveSeconds - 緩存element的有效生命期
- diskPersistent - 在VM重啟的時候是否啟用磁盤保存EhCache中的數據,默認是false。
- diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每隔120s,相應的線程會進行一次EhCache中數據的清理工作
- memoryStoreEvictionPolicy - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)
查詢緩存(Query緩存)
- 對於經常使用的查詢語句, 如果啟用了查詢緩存, 當第一次執行查詢語句時, Hibernate 會把查詢結果存放在查詢緩存中. 以后再次執行該查詢語句時, 只需從緩存中獲得查詢結果, 從而提高查詢性能
- 查詢緩存使用於如下場合:
-
- 應用程序運行時經常使用查詢語句
- 很少對與查詢語句檢索到的數據進行插入, 刪除和更新操作
-
- 使用查詢緩存的步驟
- 在 hibernate 配置文件中啟用查詢緩存
<property name="cache.use_query_cache">true</property>
- 對於希望啟用查詢緩存的查詢語句, 調用 Query 的 setCacheable(true) 方法
測試二級緩存(查詢級別的緩存進行測試)
public void classSecondCache(){ Configuration config=new Configuration().configure(); SessionFactory sf=config.buildSessionFactory(); Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //當我第一次執行查詢的時候,查詢的實體放置到類級別的緩存中 //查詢的條件(主鍵 這個條件放置查詢緩存中) Query query=session.createQuery("select o from Person o"); query.setCacheable(true); query.list(); tx.commit(); session.close(); session=sf.openSession(); tx=session.beginTransaction(); //"查詢緩存"中存放的是查詢條件,以該條件(主鍵)為准,去"類級別的緩存中"查找實體,不查數據庫 query=session.createQuery("select o from Person o"); query.setCacheable(true); query.list(); tx.commit(); session.close(); }