Session緩存其實就是一塊內(nèi)存空間,在這個內(nèi)存空間中存放了互相關(guān)聯(lián)的Java對象,Session負責根據(jù)持久化對象的狀態(tài)變化來同步更新數(shù)據(jù)庫.Session的緩存是內(nèi)置的,不能被卸載,也被稱為Hibernate的第一級緩存,此外SessionFactory有一個內(nèi)置的緩存和一個外置的緩存,其中外置的緩存是可插拔的緩存插件,也被稱為Hibernate的第二級緩存,在默認情況下,SessionFactory不會啟動這個緩存插件.
緩存的范圍和緩存的并發(fā)訪問策略
1.持久層的緩存范圍
事務(wù)范圍: 緩存只能被當前事務(wù)訪問,緩存的生命周期依賴于事務(wù)的生命周期.每個事務(wù)都有獨自的緩存
進程范圍: 緩存被進程內(nèi)的所有事務(wù)共享,緩存的生命周期依賴于進程的生命周期. 因為進程的事務(wù)有可能并發(fā)訪問緩存,所以必須對緩存采取必要的事務(wù)隔離機制;
群集范圍: 在群集環(huán)境中, 緩存被同一個機器或多個機器上的多個進程共享. 緩存中的數(shù)據(jù)被復制到集群環(huán)境中的每個進程節(jié)點,進程之間通過遠程通信來保證緩存中數(shù)據(jù)的一致性,
緩存中的數(shù)據(jù)通常采用對象的散裝數(shù)據(jù)形式;
2.緩存并發(fā)訪問策略
由上可見, 進程范圍或群集范圍緩存,即第二級緩存,會出現(xiàn)并發(fā)問題.對第二級緩存可以設(shè)定以下四種類型的并發(fā)訪問策略,每一個策略對應一種事務(wù)隔離級別.
1) 事務(wù)型: 僅僅在受管理環(huán)境中適用,對于經(jīng)常被讀但是很少被修改的數(shù)據(jù),可以防止臟讀和不可重復讀的并發(fā)問題;
2)讀寫型: 僅僅在非群集的環(huán)境中適用,對于經(jīng)常被讀但是很少被修改的數(shù)據(jù),可以防止臟讀;
3)非嚴格讀寫型: 不保證緩存與數(shù)據(jù)庫中數(shù)據(jù)的一致性,對于極少被修改,并且允許偶爾臟讀的數(shù)據(jù),可以采用這種策略;
4)只讀型: 對于從來不會被修改的數(shù)據(jù),如參考數(shù)據(jù),可以使用這個策略;
只有符合以下條件的數(shù)據(jù)才適合于存放到第二級緩存中:
1) 很少被修改的數(shù)據(jù);
2) 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾的并發(fā)問題;
3)不會被并發(fā)訪問的數(shù)據(jù);
4)參考數(shù)據(jù);
Hibernate的二級緩存SessionFactory是進程范圍或群集范圍的緩存,因此需要采用適當?shù)牟l(fā)訪問策略,提供事務(wù)隔離級別,而且可以在每個類或每個集合的粒度上配置第二級緩存.緩存適配器(Cache Provider)用于把具體的緩存實現(xiàn)軟件于Hibernate集成.Hibernate還為查詢結(jié)果提供了一個查詢緩存,它依賴于第二級緩存.
管理Hibernate的第一級緩存
Session為應用程序提供了兩個管理緩存方法evict(Object o)和clear()
evict(Object o) : 從緩存中清除參數(shù)指定的持久化對象;(適用于不希望session'按照該對象的狀態(tài)變化來同步更新數(shù)據(jù)庫和批量更新或批量刪除的場合)
clear(): 清空緩存中所有持久化對象
*對于更好的批量更新或者批量刪除的場合應該直接通過JDBC API訪問數(shù)據(jù)庫的過程, 執(zhí)行SQL語句來減少Hibernate API的多次sql執(zhí)行, 或者調(diào)用相關(guān)的存儲過程. 這個時候還得注意
Transaction接口來聲明事務(wù)邊界;
管理Hibernate的第二級緩存
由于第二級緩存是可配置的插件,Hibernate允許選用以下類型的緩存插件:
1) EHCache: 進程范圍內(nèi)的緩存, 對Hibernate的查詢緩存提供了支持;(net.sf.hibernate.cache.EhCacheProvider EHCache插件的適配器)
2) OpenSymphony OSCache: 進程范圍內(nèi)的緩存,提供了豐富的緩存數(shù)據(jù)過期策略,對Hibernate的查詢緩存提供了支持;(net.sf.hibernate.cache,OSCacheProvider OSCache插件
的適配器);
3) SwarmCache: 群集范圍的緩存,但不支持Hibernate的查詢緩存;(net.sf.hibernate.cache.SwarmCacheProvider SwarmCache插件的適配器)
4) JBossCache: 群集范圍內(nèi)的緩存,支持事務(wù)并發(fā)訪問策略,對Hibernate的查詢緩存提供了支持;(net.sf.hibernate,cache.TreeCacheProvider JBossCache插件的適配器)
配置第二級緩存主要包含以下步驟:
1) 在各個映射文件中為持久化類設(shè)置第二級緩存后者在Hibernate的配置文件hibernate.cfg.xml中集中設(shè)置第二級緩存,設(shè)置它的命名緩存的并發(fā)訪問策略;
2)選擇合適的緩存插件,手工編輯配置文件,為每個命名緩存設(shè)置數(shù)據(jù)過期策略;
<class name="mypack.Category" table="CATEGORIES">
<cache usage="read-write"/>
<id name="id" type="long" column="ID">
...
</class>
*如果只在category中配置cache,當調(diào)用category.getItems().iterate()方法時,Hibernate只會把items集合中的元素存放到緩存中,此時Hibernate僅僅把與Category關(guān)聯(lián)的Item對象的OID存放
到緩存中.如果希望把整個Item對象散裝數(shù)據(jù)存入緩存,應該在Item.hbm.xml文件中設(shè)置cache元素
***************************************************************************************************************************************************
在默認情況下,Session會在下面的時間點清理緩存.
1) 當應用程序調(diào)用net.sf.hibernate.Transaction的commit()方法的時候,commit()方法先清理緩存, 然后再向數(shù)據(jù)庫提交事務(wù);
2) 當應用程序調(diào)用Session的find()或者iterate()時, 如果緩存中持久化對象的屬性發(fā)生了變化, 就會先清理緩存, 以保證查詢結(jié)果能反映持久化對象的最新狀態(tài);
3) 當應用程序顯式調(diào)用Session的flush()方法的時候;
1. Session的save()方法
save方法并不立即執(zhí)行SQL insert語句, 只有當Session清理緩存的時, 才會執(zhí)行SQL insert語句.如果在save()方法之后, 又修改了持久化對象的屬性, 這會使得Session在清理緩
存時, 額外執(zhí)行SQL update語句.
2. Session的update()方法
update方法會生成或調(diào)用一個計劃的update語句,并且Session只有在清理緩存的時候才會執(zhí)行update語句,在執(zhí)行時才會把Customer對象當前的屬性值組裝到update語句中.
**通過update()方法使游離對象被一個Session關(guān)聯(lián),即使沒有修改Customer對象的任何屬性,Session在清理緩存時也會執(zhí)行由update()方法計劃的update語句. 如果希望Session僅僅當修
改了Customer對象的屬性時, 才執(zhí)行update語句, 可以把映射文件中<class>元素的select-before-update設(shè)為true, 該屬性的默認值為false;
**當update()方法關(guān)聯(lián)一個游離對象時, 如果在Session的緩存中已經(jīng)存在相同OID的持久化對象,會拋出異常.
3. Session的saveOrUpdate()方法
saveOrUpdate()方法同時包含了save()與update()方法的功能, 如果傳入的參數(shù)是臨時對象就調(diào)用save()方法; 如果傳入的參數(shù)是游離對象, 就調(diào)用update()方法; 如果傳入的參數(shù)
是持久化對象, 那就直接返回.
4. Session的load()和get()方法
Session的load()和get()方法都能根據(jù)給定的OID從數(shù)據(jù)庫中加載一個持久化對象, 這兩個方法的區(qū)別在于: 當數(shù)據(jù)庫中不存在與OID對應的記錄時, load()方法拋出
net.sf.hibernate.ObjectNotFoundException異常,而get()返回null.
5. Session的delete()方法
如果傳入的參數(shù)是持久化對象, Session就計劃執(zhí)行一個delete語句. 如果傳入的參數(shù)是游離對象, 先使游離對象被Session關(guān)聯(lián), 使它變?yōu)槌志没瘜ο? 然后計劃執(zhí)行一個delete語
句. Session只有在清理緩存的時候才會執(zhí)行delete語句.
該方法也能刪除多個對象, 但不推薦,效率低.如 session.delete("from Customer as c where c.id>8");
緩存的范圍和緩存的并發(fā)訪問策略
1.持久層的緩存范圍
事務(wù)范圍: 緩存只能被當前事務(wù)訪問,緩存的生命周期依賴于事務(wù)的生命周期.每個事務(wù)都有獨自的緩存
進程范圍: 緩存被進程內(nèi)的所有事務(wù)共享,緩存的生命周期依賴于進程的生命周期. 因為進程的事務(wù)有可能并發(fā)訪問緩存,所以必須對緩存采取必要的事務(wù)隔離機制;
群集范圍: 在群集環(huán)境中, 緩存被同一個機器或多個機器上的多個進程共享. 緩存中的數(shù)據(jù)被復制到集群環(huán)境中的每個進程節(jié)點,進程之間通過遠程通信來保證緩存中數(shù)據(jù)的一致性,
緩存中的數(shù)據(jù)通常采用對象的散裝數(shù)據(jù)形式;
2.緩存并發(fā)訪問策略
由上可見, 進程范圍或群集范圍緩存,即第二級緩存,會出現(xiàn)并發(fā)問題.對第二級緩存可以設(shè)定以下四種類型的并發(fā)訪問策略,每一個策略對應一種事務(wù)隔離級別.
1) 事務(wù)型: 僅僅在受管理環(huán)境中適用,對于經(jīng)常被讀但是很少被修改的數(shù)據(jù),可以防止臟讀和不可重復讀的并發(fā)問題;
2)讀寫型: 僅僅在非群集的環(huán)境中適用,對于經(jīng)常被讀但是很少被修改的數(shù)據(jù),可以防止臟讀;
3)非嚴格讀寫型: 不保證緩存與數(shù)據(jù)庫中數(shù)據(jù)的一致性,對于極少被修改,并且允許偶爾臟讀的數(shù)據(jù),可以采用這種策略;
4)只讀型: 對于從來不會被修改的數(shù)據(jù),如參考數(shù)據(jù),可以使用這個策略;
只有符合以下條件的數(shù)據(jù)才適合于存放到第二級緩存中:
1) 很少被修改的數(shù)據(jù);
2) 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾的并發(fā)問題;
3)不會被并發(fā)訪問的數(shù)據(jù);
4)參考數(shù)據(jù);
Hibernate的二級緩存SessionFactory是進程范圍或群集范圍的緩存,因此需要采用適當?shù)牟l(fā)訪問策略,提供事務(wù)隔離級別,而且可以在每個類或每個集合的粒度上配置第二級緩存.緩存適配器(Cache Provider)用于把具體的緩存實現(xiàn)軟件于Hibernate集成.Hibernate還為查詢結(jié)果提供了一個查詢緩存,它依賴于第二級緩存.
管理Hibernate的第一級緩存
Session為應用程序提供了兩個管理緩存方法evict(Object o)和clear()
evict(Object o) : 從緩存中清除參數(shù)指定的持久化對象;(適用于不希望session'按照該對象的狀態(tài)變化來同步更新數(shù)據(jù)庫和批量更新或批量刪除的場合)
clear(): 清空緩存中所有持久化對象
*對于更好的批量更新或者批量刪除的場合應該直接通過JDBC API訪問數(shù)據(jù)庫的過程, 執(zhí)行SQL語句來減少Hibernate API的多次sql執(zhí)行, 或者調(diào)用相關(guān)的存儲過程. 這個時候還得注意
Transaction接口來聲明事務(wù)邊界;
管理Hibernate的第二級緩存
由于第二級緩存是可配置的插件,Hibernate允許選用以下類型的緩存插件:
1) EHCache: 進程范圍內(nèi)的緩存, 對Hibernate的查詢緩存提供了支持;(net.sf.hibernate.cache.EhCacheProvider EHCache插件的適配器)
2) OpenSymphony OSCache: 進程范圍內(nèi)的緩存,提供了豐富的緩存數(shù)據(jù)過期策略,對Hibernate的查詢緩存提供了支持;(net.sf.hibernate.cache,OSCacheProvider OSCache插件
的適配器);
3) SwarmCache: 群集范圍的緩存,但不支持Hibernate的查詢緩存;(net.sf.hibernate.cache.SwarmCacheProvider SwarmCache插件的適配器)
4) JBossCache: 群集范圍內(nèi)的緩存,支持事務(wù)并發(fā)訪問策略,對Hibernate的查詢緩存提供了支持;(net.sf.hibernate,cache.TreeCacheProvider JBossCache插件的適配器)
配置第二級緩存主要包含以下步驟:
1) 在各個映射文件中為持久化類設(shè)置第二級緩存后者在Hibernate的配置文件hibernate.cfg.xml中集中設(shè)置第二級緩存,設(shè)置它的命名緩存的并發(fā)訪問策略;
2)選擇合適的緩存插件,手工編輯配置文件,為每個命名緩存設(shè)置數(shù)據(jù)過期策略;
<class name="mypack.Category" table="CATEGORIES">
<cache usage="read-write"/>
<id name="id" type="long" column="ID">
...
</class>
*如果只在category中配置cache,當調(diào)用category.getItems().iterate()方法時,Hibernate只會把items集合中的元素存放到緩存中,此時Hibernate僅僅把與Category關(guān)聯(lián)的Item對象的OID存放
到緩存中.如果希望把整個Item對象散裝數(shù)據(jù)存入緩存,應該在Item.hbm.xml文件中設(shè)置cache元素
***************************************************************************************************************************************************
在默認情況下,Session會在下面的時間點清理緩存.
1) 當應用程序調(diào)用net.sf.hibernate.Transaction的commit()方法的時候,commit()方法先清理緩存, 然后再向數(shù)據(jù)庫提交事務(wù);
2) 當應用程序調(diào)用Session的find()或者iterate()時, 如果緩存中持久化對象的屬性發(fā)生了變化, 就會先清理緩存, 以保證查詢結(jié)果能反映持久化對象的最新狀態(tài);
3) 當應用程序顯式調(diào)用Session的flush()方法的時候;
1. Session的save()方法
save方法并不立即執(zhí)行SQL insert語句, 只有當Session清理緩存的時, 才會執(zhí)行SQL insert語句.如果在save()方法之后, 又修改了持久化對象的屬性, 這會使得Session在清理緩
存時, 額外執(zhí)行SQL update語句.
2. Session的update()方法
update方法會生成或調(diào)用一個計劃的update語句,并且Session只有在清理緩存的時候才會執(zhí)行update語句,在執(zhí)行時才會把Customer對象當前的屬性值組裝到update語句中.
**通過update()方法使游離對象被一個Session關(guān)聯(lián),即使沒有修改Customer對象的任何屬性,Session在清理緩存時也會執(zhí)行由update()方法計劃的update語句. 如果希望Session僅僅當修
改了Customer對象的屬性時, 才執(zhí)行update語句, 可以把映射文件中<class>元素的select-before-update設(shè)為true, 該屬性的默認值為false;
**當update()方法關(guān)聯(lián)一個游離對象時, 如果在Session的緩存中已經(jīng)存在相同OID的持久化對象,會拋出異常.
3. Session的saveOrUpdate()方法
saveOrUpdate()方法同時包含了save()與update()方法的功能, 如果傳入的參數(shù)是臨時對象就調(diào)用save()方法; 如果傳入的參數(shù)是游離對象, 就調(diào)用update()方法; 如果傳入的參數(shù)
是持久化對象, 那就直接返回.
4. Session的load()和get()方法
Session的load()和get()方法都能根據(jù)給定的OID從數(shù)據(jù)庫中加載一個持久化對象, 這兩個方法的區(qū)別在于: 當數(shù)據(jù)庫中不存在與OID對應的記錄時, load()方法拋出
net.sf.hibernate.ObjectNotFoundException異常,而get()返回null.
5. Session的delete()方法
如果傳入的參數(shù)是持久化對象, Session就計劃執(zhí)行一個delete語句. 如果傳入的參數(shù)是游離對象, 先使游離對象被Session關(guān)聯(lián), 使它變?yōu)槌志没瘜ο? 然后計劃執(zhí)行一個delete語
句. Session只有在清理緩存的時候才會執(zhí)行delete語句.
該方法也能刪除多個對象, 但不推薦,效率低.如 session.delete("from Customer as c where c.id>8");