當前位置:首頁 » 文件管理 » hibernateehcache緩存

hibernateehcache緩存

發布時間: 2022-10-06 01:38:04

① hibernate緩存的詳細配置

很多人對二級緩存都不太了解,或者是有錯誤的認識,我一直想寫一篇文章介紹一下hibernate的二級緩存的,今天終於忍不住了。
我的經驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。

hibernate的session提供了一級緩存,每個session,對同一個id進行兩次load,不會發送兩條sql資料庫,但是session關閉的時候,一級緩存就失效了。

二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設置hibernate.cache.provider_class,我們這里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查詢緩存,加上
hibernate.cache.use_query_cache=true

緩存可以簡單的看成一個Map,通過key在緩存裡面找value。

Class的緩存
對於一條記錄,也就是一個PO來說,是根據ID來找的,緩存的key就是ID,value是POJO。無論list,load還是iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取資料庫select id出來,然後一個id一個id的load,如果在緩存裡面有,就從緩存取,沒有的話就去資料庫load。假設是讀寫緩存,需要設置:
<cache usage="read-write"/>
如果你使用的二級緩存實現是ehcache的話,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示緩存是不是永遠不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如果eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發呆時間,是可選的。當往緩存裡面put的元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分數據保存在硬碟上的臨時文件裡面。
每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然後使用defaultCache的配置,這樣多個class會共享一個配置。
當某個ID通過hibernate修改時,hibernate會知道,於是移除緩存。
這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什麼時候是第一次,而且每次查詢的條件通常是不一樣的,假如資料庫裡面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次iterate的時候卻查詢到30至70號id,那麼30-50是從緩存裡面取的,51到70是從資料庫取的,共發送1+20條sql。所以我一直認為iterate沒有什麼用,總是會有1+N的問題。
(題外話:有說法說大型查詢用list會把整個結果集裝入內存,很慢,而iterate只select id比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結果集裝進來,假如一頁20條的話,iterate共需要執行21條語句,list雖然選擇若干欄位,比iterate第一條select id語句慢一些,但只有一條語句,不裝入整個結果集hibernate還會根據資料庫方言做優化,比如使用mysql的limit,整體看來應該還是list快。)
如果想要對list或者iterate查詢的結果緩存,就要用到查詢緩存了

查詢緩存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以後不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然後
query.setCacheable(true);//激活查詢緩存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選
第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個查詢緩存做一個單獨的配置,使用setCacheRegion來做這個指定,需要在ehcache.xml裡面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不設置cacheRegion的話,那麼會使用上面提到的標准查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

對於查詢緩存來說,緩存的key是根據hql生成的sql,再加上參數,分頁等信息(可以通過日誌輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
參數是"tiger%",那麼查詢緩存的key*大約*是這樣的字元串(我是憑記憶寫的,並不精確,不過看了也該明白了):
select * from cat c where c.name like ? , parameter:tiger%
這樣,保證了同樣的查詢、同樣的參數等條件下具有一樣的key。
現在說說緩存的value,如果是list方式的話,value在這里並不是整個結果集,而是查詢出來的這一串ID。也就是說,不管是list方法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執行一條sql,iterate執行1+N條,多出來的行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據緩存的key去緩存裡面查到了value,value是一串id,然後在到class的緩存裡面去一個一個的load出來。這樣做是為了節約內存。
可以看出來,查詢緩存需要打開相關類的class緩存。list和iterate方法第一次執行的時候,都是既填充查詢緩存又填充class緩存的。
這里還有一個很容易被忽視的重要問題,即打開查詢緩存以後,即使是list方法也可能遇到1+N的問題!相同條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數據,總是發送一條sql語句到資料庫獲取全部數據,然後填充查詢緩存和class緩存。但是第二次執行的時候,問題就來了,如果你的class緩存的超時時間比較短,現在class緩存都超時了,但是查詢緩存還在,那麼list方法在獲取id串以後,將會一個一個去資料庫load!因此,class緩存的超時時間一定不能短於查詢緩存設置的超時時間!如果還設置了發呆時間的話,保證class緩存的發呆時間也大於查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意了。

另外,如果hql查詢包含select字句,那麼查詢緩存裡面的value就是整個結果集了。

當hibernate更新資料庫的時候,它怎麼知道更新哪些查詢緩存呢?
hibernate在一個地方維護每個表的最後更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置裡面。
當通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然後它更新這些表的最後更新時間。每個緩存都有一個生成時間和這個緩存所查詢的表,當hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然後去查找這些表的最後更新時間,如果有一個表在生成時間後更新過了,那麼這個緩存是無效的。
可以看出,只要更新過一個表,那麼凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

Collection緩存
需要在hbm的collection裡面設置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那麼ehcache裡面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就失效,一個collection緩存僅在這個collection裡面的元素有增刪時才失效。
這樣有一個問題,如果你的collection是根據某個欄位排序的,當其中一個元素更新了該欄位時,導致順序改變時,collection緩存裡面的順序沒有做更新。

緩存策略
只讀緩存(read-only):沒有什麼好說的
讀/寫緩存(read-write):程序可能要的更新數據
不嚴格的讀/寫緩存(nonstrict-read-write):需要更新數據,但是兩個事務更新同一條記錄的可能性很小,性能比讀寫緩存好
事務緩存(transactional):緩存支持事務,發生異常的時候,緩存也能夠回滾,只支持jta環境,這個我沒有怎麼研究過

讀寫緩存和不嚴格讀寫緩存在實現上的區別在於,讀寫緩存更新緩存的時候會把緩存裡面的數據換成一個鎖,其他事務如果去取相應的緩存數據,發現被鎖住了,然後就直接取資料庫查詢。
在hibernate2.1的ehcache實現中,如果鎖住部分緩存的事務發生了異常,那麼緩存會一直被鎖住,直到60秒後超時。
不嚴格讀寫緩存不鎖定緩存中的數據。

使用二級緩存的前置條件
你的hibernate程序對資料庫有獨占的寫訪問權,其他的進程更新了資料庫,hibernate是不可能知道的。你操作資料庫必需直接通過hibernate,如果你調用存儲過程,或者自己使用jdbc更新資料庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪除是不更新二級緩存的,但是據說3.1已經解決了這個問題。
這個限制相當的棘手,有時候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優化,很郁悶吧。
SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調用這些方法移除緩存,這些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不過我不建議這樣做,因為這樣很難維護。比如你現在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用evictQueries(String cacheRegion)移除了3個查詢緩存,然後用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關查詢緩存,可能會忘記更新這里的移除代碼。如果你的jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什麼地方也要做相應的改動嗎?

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

總結:
不要想當然的以為緩存一定能提高性能,僅僅在你能夠駕馭它並且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當的使用還可能導致讀出臟數據。
如果受不了hibernate的諸多限制,那麼還是自己在應用程序的層面上做緩存吧。
在越高的層面上做緩存,效果就會越好。就好像盡管磁碟有緩存,資料庫還是要實現自己的緩存,盡管資料庫有緩存,咱們的應用程序還是要做緩存。因為底層的緩存它並不知道高層要用這些數據干什麼,只能做的比較通用,而高層可以有針對性的實現緩存,所以在更高的級別上做緩存,效果也要好些吧。

② 什麼是hibernate中的二級緩存

第一級別的緩存是Session級別的緩存,是屬於事務范圍的緩存,由Hibernate管理,一般無需進行干預。第二級別的緩存是SessionFactory級別的緩存,是屬於進程范圍的緩存。


二級緩存也分為了兩種

內置緩存:Hibernate自帶的,不可卸載,通常在Hibernate的初始化階段,Hibernate會把映射元數據和預定義的SQL語句放置到SessionFactory的緩存中。該內置緩存是只讀的。

外置緩存:通常說的二級緩存也就是外置緩存,在默認情況下SessionFactory不會啟用這個緩存插件,外置緩存中的數據是資料庫數據的復制,外置緩存的物理介質可以是內存或者硬碟。

hibernate二級緩存的結構


2.並發訪問策略

transactional

(事務型)

僅在受管理的環境中適用

提供Repeatable Read事務隔離級別

適用經常被讀,很少修改的數據

可以防止臟讀和不可重復讀的並發問題

緩存支持事務,發生異常的時候,緩存也能夠回滾

read-write

(讀寫型)

提供Read Committed事務隔離級別

在非集群的環境中適用

適用經常被讀,很少修改的數據

可以防止臟讀

更新緩存的時候會鎖定緩存中的數據

nonstrict-read-write

(非嚴格讀寫型)

適用極少被修改,偶爾允許臟讀的數據(兩個事務同時修改數據的情況很少見)

不保證緩存和資料庫中數據的一致性

為緩存數據設置很短的過期時間,從而盡量避免臟讀

不鎖定緩存中的數據

read-only

(只讀型)

適用從來不會被修改的數據(如參考數據)

在此模式下,如果對數據進行更新操作,會有異常

事務隔離級別低,並發性能高

在集群環境中也能完美運作

分析:通過上述表格分析如下

適合放入二級緩存中數據

很少被修改

不是很重要的數據,允許出現偶爾的並發問題

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

經常被修改

財務數據,絕對不允許出現並發問題

與其他應用數據共享的數據


③ hibernate二級緩存什麼時候用

Hibernate緩存何時使用和如何使用?

Hibernate緩存分為二級,第一級存放於session中稱為一級緩存,默認帶有且不能卸載。第二級是由sessionFactory控制的進程級緩存。是全局共享的緩存,凡是會調用二級緩存的查詢方法 都會從中受益。

1. 關於hibernate緩存的問題:

1.1. 基本的緩存原理

Hibernate緩存分為二級,

第一級存放於session中稱為一級緩存,默認帶有且不能卸載。

第二級是由sessionFactory控制的進程級緩存。是全局共享的緩存,凡是會調用二級緩存的查詢方法 都會從中受益。只有經正確的配置後二級緩存才會發揮作用。同時在進行條件查詢時必須使用相應的方法才能從緩存中獲取數據。比如 Query.iterate()方法、load、get方法等。必須注意的是session.find方法永遠是從資料庫中獲取數據,不會從二級緩存中獲 取數據,即便其中有其所需要的數據也是如此。

查詢時使用緩存的實現過程為:首先查詢一級緩存中是否具有需要的數據,如果沒有,查詢二級緩存,如果二級緩存中也沒有,此時再執行查詢資料庫的工作。要注意的是:此3種方式的查詢速度是依次降低的。

1.2. 存在的問題

1.2.1. 一級緩存的問題以及使用二級緩存的原因

因為Session的生命期往往很短,存在於Session內部的第一級最快緩存的生命期當然也很短,所以第一級緩存的命中率是很低的。其對系統性 能的改善也是很有限的。當然,這個Session內部緩存的主要作用是保持Session內部數據狀態同步。並非是hibernate為了大幅提高系統性 能所提供的。

為了提高使用hibernate的性能,除了常規的一些需要注意的方法比如:

使用延遲載入、迫切外連接、查詢過濾等以外,還需要配置hibernate的二級緩存。其對系統整體性能的改善往往具有立竿見影的效果!

(經過自己以前作項目的經驗,一般會有3~4倍的性能提高)

1.2.2. N+1次查詢的問題

1.2.2.1 什麼時候會遇到1+N的問題?

前提:Hibernate默認表與表的關聯方法是fetch="select",不是fetch="join",這都是為了懶載入而准備的。

1)一對多(<set><list>) ,在1的這方,通過1條sql查找得到了1個對象,由於關聯的存在 ,那麼又需要將這個對象關聯的集合取出,所以合集數量是n還要發出n條sql,於是本來的1條sql查詢變成了1 +n條 。

2)多對一<many-to-one> ,在多的這方,通過1條sql查詢得到了n個對象,由於關聯的存在,也會將這n個對象對應的1 方的對象取出, 於是本來的1條sql查詢變成了1 +n條 。

3)iterator 查詢時,一定先去緩存中找(1條sql查集合,只查出ID),在沒命中時,會再按ID到庫中逐一查找, 產生1+n條SQL

1.2.2.2 怎麼解決1+N 問題?

1 )lazy=true, hibernate3開始已經默認是lazy=true了;lazy=true時不會立刻查詢關聯對象,只有當需要關聯對象(訪問其屬性,非id欄位)時才會發生查詢動作。

2)使用二級緩存, 二級緩存的應用將不怕1+N 問題,因為即使第一次查詢很慢(未命中),以後查詢直接緩存命中也是很快的。剛好又利用了1+N 。

3) 當然你也可以設定fetch="join",一次關聯表全查出來,但失去了懶載入的特性。

執行條件查詢時,iterate()方法具有著名的 「n+1」次查詢的問題,也就是說在第一次查詢時iterate方法會執行滿足條件的查詢結果數再加一次(n+1)的查詢。但是此問題只存在於第一次查詢 時,在後面執行相同查詢時性能會得到極大的改善。此方法適合於查詢數據量較大的業務數據。

但是注意:當數據量特別大時(比如流水線數據等)需要針對此持久化對象配置其具體的緩存策略,比如設置其存在於緩存中的最大記錄數、緩存存在的時間等參數,以避免系統將大量的數據同時裝載入內存中引起內存資源的迅速耗盡,反而降低系統的性能!!!

1.3. 使用hibernate二級緩存的其他注意事項:

1.3.1. 關於數據的有效性

另外,hibernate會自行維護二級緩存中的數據,以保證緩存中的數據和資料庫中的真實數據的一致性!無論何時,當你調用save()、 update()或 saveOrUpdate()方法傳遞一個對象時,或使用load()、 get()、list()、iterate() 或scroll()方法獲得一個對象時, 該對象都將被加入到Session的內部緩存中。 當隨後flush()方法被調用時,對象的狀態會和資料庫取得同步。

也就是說刪除、更新、增加數據的時候,同時更新緩存。當然這也包括二級緩存!

只要是調用hibernate API執行資料庫相關的工作。hibernate都會為你自動保證 緩存數據的有效性!!

但是,如果你使用了JDBC繞過hibernate直接執行對資料庫的操作。此時,Hibernate不會/也不可能自行感知到資料庫被進行的變化改動,也就不能再保證緩存中數據的有效性!!

這也是所有的ORM產品共同具有的問題。幸運的是,Hibernate為我們暴露了Cache的清除方法,這給我們提供了一個手動保證數據有效性的機會!!

一級緩存,二級緩存都有相應的清除方法。

其中二級緩存提供的清除方法為:

按對象class清空緩存

按對象class和對象的主鍵id清空緩存

清空對象的集合中的緩存數據等。

1.3.2. 適合使用的情況

並非所有的情況都適合於使用二級緩存,需要根據具體情況來決定。同時可以針對某一個持久化對象配置其具體的緩存策略。

適合於使用二級緩存的情況:

1、數據不會被第三方修改;

一般情況下,會被hibernate以外修改的數據最好不要配置二級緩存,以免引起不一致的數據。但是如果此數據因為性能的原因需要被緩存,同時又 有可能被第3方比如SQL修改,也可以為其配置二級緩存。只是此時需要在sql執行修改後手動調用cache的清除方法。以保證數據的一致性

2、數據大小在可接收范圍之內;

如果數據表數據量特別巨大,此時不適合於二級緩存。原因是緩存的數據量過大可能會引起內存資源緊張,反而降低性能。
如果數據表數據量特別巨大,但是經常使用的往往只是較新的那部分數據。此時,也可為其配置二級緩存。但是必須單獨配置其持久化類的緩存策略,比如最大緩存數、緩存過期時間等,將這些參數降低至一個合理的范圍(太高會引起內存資源緊張,太低了緩存的意義不大)。

3、數據更新頻率低;

對於數據更新頻率過高的數據,頻繁同步緩存中數據的代價可能和 查詢緩存中的數據從中獲得的好處相當,壞處益處相抵消。此時緩存的意義也不大。

4、非關鍵數據(不是財務數據等)

財務數據等是非常重要的數據,絕對不允許出現或使用無效的數據,所以此時為了安全起見最好不要使用二級緩存。

因為此時 「正確性」的重要性遠遠大於 「高性能」的重要性。

2. 目前系統中使用hibernate緩存的建議

2.1. 目前情況

一般系統中有三種情況會繞開hibernate執行資料庫操作:

1、多個應用系統同時訪問一個資料庫

此種情況使用hibernate二級緩存會不可避免的造成數據不一致的問題,此時要進行詳細的設計。比如在設計上避免對同一數據表的同時的寫入操作,
使用資料庫各種級別的鎖定機制等。

2、動態表相關

所謂「動態表」是指在系統運行時根據用戶的操作系統自動建立的數據表。

比如「自定義表單」等屬於用戶自定義擴展開發性質的功能模塊,因為此時數據表是運行時建立的,所以不能進行hibernate的映射。因此對它的操作只能是繞開hibernate的直接資料庫JDBC操作。

如果此時動態表中的數據沒有設計緩存,就不存在數據不一致的問題。

如果此時自行設計了緩存機制,則調用自己的緩存同步方法即可。

3、使用sql對hibernate持久化對象表進行批量刪除時

此時執行批量刪除後,緩存中會存在已被刪除的數據。

分析:

當執行了第3條(sql批量刪除)後,後續的查詢只可能是以下三種方式:

a. session.find()方法:

根據前面的總結,find方法不會查詢二級緩存的數據,而是直接查詢資料庫。

所以不存在數據有效性的問題。

b. 調用iterate方法執行條件查詢時:

根據iterate查詢方法的執行方式,其每次都會到資料庫中查詢滿足條件的id值,然後再根據此id 到緩存中獲取數據,當緩存中沒有此id的數據才會執行資料庫查詢;

如果此記錄已被sql直接刪除,則iterate在執行id查詢時不會將此id查詢出來。所以,即便緩存中有此條記錄也不會被客戶獲得,也就不存在不一致的情況。(此情況經過測試驗證)

c. 用get或load方法按id執行查詢:

客觀上此時會查詢得到已過期的數據。但是又因為系統中執行sql批量刪除一般是針對中間關聯數據表,對於中間關聯表的查詢一般都是採用條件查詢 ,按id來查詢某一條關聯關系的幾率很低,所以此問題也不存在!

如果某個值對象確實需要按id查詢一條關聯關系,同時又因為數據量大使用 了sql執行批量刪除。當滿足此兩個條件時,為了保證按id 的查詢得到正確的結果,可以使用手動清楚二級緩存中此對象的數據的方法!!(此種情況出現的可能性較小)

2.2. 建 議

1、建議不要使用sql直接執行數據持久化對象的數據的更新,但是可以執行 批量刪除。(系統中需要批量更新的地方也較少)

2、如果必須使用sql執行數據的更新,必須清空此對象的緩存數據。調用

SessionFactory.evict(class)

SessionFactory.evict(class,id)等方法。

3、在批量刪除數據量不大的時候可以直接採用hibernate的批量刪除,這樣就不存在繞開hibernate執行sql產生的緩存數據一致性的問題。

4、不推薦採用hibernate的批量刪除方法來刪除大批量的記錄數據。

原因是hibernate的批量刪除會執行1條查詢語句外加 滿足條件的n條刪除語句。而不是一次執行一條條件刪除語句!!
當待刪除的數據很多時會有很大的性能瓶頸!!!如果批量刪除數據量較大,比如超過50條,可以採用JDBC直接刪除。這樣作的好處是只執行一條sql刪除語句,性能會有很大的改善。同時,緩存數據同步的問題,可以採用 hibernate清除二級緩存中的相關數據的方法。

調 用

SessionFactory.evict(class) ;

SessionFactory.evict(class,id)等方法。

所以說,對於一般的應用系統開發而言(不涉及到集群,分布式數據同步問題等),因為只在中間關聯表執行批量刪除時調用了sql執行,同時中間關聯表 一般是執行條件查詢不太可能執行按id查詢。所以,此時可以直接執行sql刪除,甚至不需要調用緩存的清除方法。這樣做不會導致以後配置了二級緩存引起數 據有效性的問題。

退一步說,即使以後真的調用了按id查詢中間表對象的方法,也可以通過調用清除緩存的方法來解決。

3、具體的配置方法

根據我了解的很多hibernate的使用者在調用其相應方法時都迷信的相信「hibernate會自行為我們處理性能的問題」,或者 「hibernate 會自動為我們的所有操作調用緩存」,實際的情況是hibernate雖然為我們提供了很好的緩存機制和擴展緩存框架的支持,但是必須經過正確的調用其才有 可能發揮作用!!所以造成很多使用hibernate的系統的性能問題,實際上並不是hibernate不行或者不好,而是因為使用者沒有正確的了解其使 用方法造成的。相反,如果配置得當hibernate的性能表現會讓你有相當「驚喜的」發現。下面我講解具體的配置方法。

ibernate提供了二級緩存的介面:

net.sf.hibernate.cache.Provider,

同時提供了一個默認的 實現net.sf.hibernate.cache.HashtableCacheProvider,

也可以配置 其他的實現 比如ehcache,jbosscache等。

具體的配置位置位於hibernate.cfg.xml文件中

  • <propertyname="hibernate.cache.use_query_cache">true</property>

  • <propertyname="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</property>

  • 很多的hibernate使用者在 配置到 這一步 就以為 完事了,

    注意:其實光這樣配,根本就沒有使用hibernate的二級緩存。同時因為他們在使用hibernate時大多時候是馬上關閉session,所 以,一級緩存也沒有起到任何作用。結果就是沒有使用任何緩存,所有的hibernate操作都是直接操作的資料庫!!性能可以想見。

    正確的辦法是除了以上的配置外還應該配置每一個vo對象的具體緩存策略,在影射文件中配置。例如:

  • <hibernate-mapping>

  • <classname="com.sobey.sbm.model.entitySystem.vo.DataTypeVO"table="dcm_datatype">

  • <cacheusage="read-write"/>

  • <idname="id"column="TYPEID"type="java.lang.Long">

  • <generatorclass="sequence"/>

  • </id>

  • <propertyname="name"column="NAME"type="java.lang.String"/>

  • <propertyname="dbType"column="DBTYPE"type="java.lang.String"/>

  • </class>

  • </hibernate-mapping>

  • 關鍵就是這個<cache usage="read-write"/>,其有幾個選擇read-only,read-write,transactional,等

    然後在執行查詢時 注意了 ,如果是條件查詢,或者返回所有結果的查詢,此時session.find()方法 不會獲取緩存中的數據。只有調用query.iterate()方法時才會調緩存的數據。

    同時 get 和 load方法 是都會查詢緩存中的數據

④ Hibernate中使用的緩存引擎Ehcache和OSCache各自有什麼優缺點

ehcache主要是對資料庫訪問的緩存,相同的查詢語句只需查詢一次資料庫,從而提高了查詢的速度
oscache 主要是對頁面的緩存,可以整頁或者指定網頁某一部分緩存,同時指定他的過期時間,這樣在此時間段裡面訪問的數據都是一樣的

hibernate2以前提倡用ehcache
hibernate3後提倡oscache,

⑤ 在配置Hibernate二級緩存的時候,在ehcache.xml中 有這么一句 <diskStore path="D:\cache"/>

你的理解基本上是正確的,但還要結合overflowToDisk參數來用。

另外cache文件不需要手動創建。

下面是一些說明:

由於配置文件中只能指定maxElementsInMemory,這就會有可能存入的對象太多而超出VM的heap大小,當然你可以通過jvm參數增大heap大小,但這總還是有可能溢出。這里可以把maxElementsInMemory值設置到一個比較安全的大小,自己預先測試一下最好。如果內存仍然存不下你需要存的對象個數,那麼可以開啟overflowToDisk來增加可以存儲的Element個數。這里要注意一下,EHCache不會自動幫助你去把內存對象寫入到磁碟,當超過maxElementsInMemory程序會自動把更多的部分開始往硬碟寫,但是內存的對象其實並沒有清出去,這時需要手動使用Cache.flush()方法來把內存對象

重建上一次運行的緩存:這個需求肯定比較普遍,我們當然不希望一旦程序退出,整個緩存就要重建了。開啟diskPersistent功能,只要使用的是CacheManager單例模式,下一次啟動的時候就會調用上一次運行的緩存。比較麻煩的是寫入磁碟的時間還是要自己調用Cache.flush()方法。如果僅僅考慮到程序重啟的話,我建議這里把diskStore寫入到一個ramfs,這樣性能就更高了,但重啟電腦的話就不得不重建緩存了。

⑥ hibernate二級緩存配置,系統提示找不到ehcache.xml的配置文件

你的jar包都沒有,肯定解析不了啊!!!

⑦ 怎麼開啟hibernate的緩存

1 緩存的概念,以及用途
1) 緩存:(hibernate單獨用來保存數據,開辟一塊內存)
緩存就是資料庫中的數據在內存中的臨時的容器,包含
了資料庫表中的數據,位於資料庫和訪問層之間
2)緩存優點: hibernate做查詢的時候,首先去緩存中
查詢要找的數據,有直接使用,沒有再發sql語句去資料庫
中真實查詢
把用戶經常訪問的數據,放入緩存當中,這樣每次
就不需要去資料庫中訪問這些常用信息,可以提高系統的
性能。
3)緩存的分類:
a) 一級緩存
b) 二級緩存
c) 查詢緩存

2 一級緩存
1)內部結構:一級緩存的內部結構就是一個map<id,object>
map的key就是id,map的value就是實體對象,該結構
導致一級緩存不能緩存屬性
2)一級緩存的生命周期:
一級緩存的生命周期與session有關,session創建並
維護一級緩存,session關閉,一級緩存銷毀
3)hibernate中API使用緩存:
a) 可以讀寫一級緩存的: get , load,Iterate
b) 可以寫入一級緩存的: save ,list
4)hibernate一級緩存無法禁用:
5)一級緩存的管理:session管理一級緩存(把一級緩存
數據清空clear)

3 二級緩存
1)二級緩存也叫進程級緩存或SessionFactory級緩存,
二級緩存可以讓所有的session所共享
2)二級緩存的生命周期跟SessionFactory一致,
SessionFactory管理二級緩存
3)二級緩存的結構是Hashtable,只能保持實體對象,
不能保存屬性,開發當中需要使用第3方提供的緩存組件
4)ehcache.xml
//在該二級緩存中,最多可以緩存對象的數量
maxElementsInMemory="1000"
//緩存在二級緩存中的對象是否永遠都有效,一般配置為false
eternal="true"
//"鈍化":兩次訪問該二級緩存中對象的,間隔時間
timeToIdleSeconds="120"
//二級緩存中的對象從創建到消亡的時間
timeToLiveSeconds="120"
//如果超過緩存的訪問,可以寫入到硬碟上的
overflowToDisk="true"
5)如何使用二級緩存
a)導入第3方ehcache-1.2.3.jar
b)導入ehcache.xml 配置文件,放入src目錄下
c)修改hibernate.cfg.xml
(一)指明二級緩存的提供商
<!-- 指明二級緩存的提供商 -->
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
(二)開啟二級緩存
<!-- 是否開啟二級緩存,true開啟二級緩存,false關閉二級緩存 -->
<property name="cache.use_second_level_cache">true</property>
d)指明那個對象放入二級緩存中
<!-- 指定把那個對象放入二級緩存當中 -->
<class-cache class="com.tarena.po.Student" usage="read-only"/>
6) 使用二級緩存
能夠讀寫二級緩存: get load iterate
能夠寫入而不能讀取二級緩存: list
7) 二級緩存的管理
使用SessionFactory來管理我們的二級緩存
首先修改HibernateUtil,添加獲得SessionFactory的方法
SessionFactory factory = HibernateUtil2.getSessionFactory();
//factory.evict(Student.class, 1):去掉二級緩存中
//id為1的student對象
//factory.evict(Student.class,1);
//factory.evict(Student.class):去掉二級緩存中所有的
//student對象

4 查詢緩存
1)查詢用來保存屬性的,對實體對象的結果集只保存id
2)查詢緩存的生命周期,只有當前的表發生改變,查詢
緩存的生命周期結束
3)如何使用查詢緩存:
a)修改hibernate.cfg.xml文件,開啟查詢緩存
<!-- 是否開啟查詢緩存,true開啟查詢緩存,false關閉查詢緩存 -->
<property name="cache.use_query_cache">true</property>
b)在Query對象中必須手動開啟查詢緩存

⑧ 關於Hibernate二級緩存的問題

<property
name="hibernate.cache.use_second_level_cache">true</property>
<property
name="hibernate.cache.provider_class">org.hibernate.cache.ehcacheprovider</property>
前一句是打開二級緩存,後一句是啟用第三方緩存產品(可改變,上面eache是hibernate官方默認的第三方緩存產品)
緩存是否實用,要看你的需求,
如果你的系統,瀏覽的人數比較多,但是增刪的比較少,緩存的功勞非常大
如果你的系統即時性非常強,那麼緩存的命中率就比較低,同時更新數據時,hibernate需要額外提供資源維護緩存與數據的一致

⑨ hibernate二級緩存,ehcache.xml文件在哪

合理的緩存應用可以極大地提高系統性能,最簡單的是在應用層面做緩存(越高層面做緩存,效果往往越好),直接將數據緩存到伺服器中,以全局map方式存儲。在使用的時候直接從緩存的map中取,而不用連接資料庫,從而提升性能。這種方式簡單易行,但是map常駐伺服器內存,並且在數據變更(增刪改)的時候要手動更新map。還有一種方式比較通用,就是使用Hibernate二級緩存(SessionFactory級別的全局緩存,進程或集群級別),是一種通用緩存(一級緩存就不說了,Session級別緩存,hibernate自己管理),hibernate二級緩存多應用在多讀少寫的實體對象中,比如組織機構和系統字典。本文使用hibernate註解方式使用二級緩存,做一個說明(使用Ehcache)。1、添加ehcache.xml配置文件2、hibernate配置文件中,配置Ehcache相關屬性hibernate.cache.use_second_level_cache=truehibernate.cache.use_query_cache=truehibernate.cache.provider_class=org.hibernate.cache.EhCacheProviderhibernate.generate_statistics=true調試的時候,可以設置log4j的log4j.logger.org.hibernate.cache=debug(記錄二級緩存的活動),實際發布的時候,注釋掉,以免影響性能。3、pom文件中引入相應jar包(Maven項目,如果還在手動添加jar包的,可以嘗試使用maven)org.hibernatehibernate-ehcache3.6.9.Final4、註解方式配置實體配置了二級緩存後,並不是對所有的實體使用,而是需要指定哪些實體需要用到。如果不配置查詢緩存(查詢緩存會在下面講到),則只會在根據id查詢的操作中,緩存對象。在實體上配置@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)並指定緩存並發策略。@Entity@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)@Table(name="base_dict")@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler","parentDict"}){/****/=5569761987303812150L;@Id@Column(name="id",length=36)@GeneratedValue(generator="uuid")@GenericGenerator(name="uuid",strategy="org.hibernate.id.UUIDGenerator")@JsonProperty("id")privateStringid;/**字典名稱*/@ForeignShow@Column(name="name",length=200)privateStringname;5、查詢緩存的使用Queryquery=session.createQuery(hql);query.setCacheable(true);//啟用查詢緩存query.setCacheRegion(「queryCacheRegion」);//設置查詢緩存區域(數據過期策略)QueryCache只是在特定的條件下才會發揮作用,而且要求相當嚴格:(1)完全相同的HQL重復執行。(注意,只有hql)(2)重復執行期間,QueryCache對應的數據表不能有數據變動(比如添、刪、改操作)絕大多數的查詢並不能從查詢緩存中受益,所以Hibernate默認是不進行查詢緩存的。查詢緩存適用於以下場合:(1)在應用程序運行時經常使用的查詢語句(參數相同)(2)很少對與查詢語句檢索到的數據進行插入、刪除或更新操作query.list();

⑩ ehcache java 對象緩存怎麼實現

1.技術背景:
系統緩存是位於應用程序與物理數據源之間,用於臨時存放復制數據的內存區域,目的是為減少應用程序對物理數據源訪問的次數,從而提高應用程序的運行性能。緩存設想內存是有限的,緩存的時效性也是有限的,所以可以設定內存數量的大小可以執行失效演算法,可以在內存滿了的情況下,按照最少訪問等演算法將緩存直接移除或切換到硬碟上。
Ehcache從Hibernate發展而來,逐漸涵蓋了Cache界的全部功能,是目前發展勢頭最好的一個項目,具有快速、簡單、低消耗、擴展性強、支持對象或序列化緩存,支持緩存或元素的失效,提供LRU、LFU和FIFO緩存策略,支持內存緩存和硬碟緩存和分布式緩存機制等特點。其中Cache的存儲方式為內存或磁碟(ps:無須擔心容量問題)
2.EhCahe的類層次介紹:
主要分為三層,最上層是CacheManager,它是操作Ehcache的入口。可以通過CacheManager.getInstance()獲得一個單子的CacheManager,或者通過CacheManager的構造函數創建一個新的CacheManager。每個CacheManger都管理多個Cache。每個Cache都以一種類Hash的方式,關聯多個Element。Element就是我們用於存放緩存內容的地方。
3.環境搭建:
很簡單只需要將ehcache-2.1.0-distribution.tar.gz和ehcache-web-2.0.2-distribution.tar.gz擠壓的jar包放入WEB-INF/lib下。
再創建一個重要的配置文件ehcache.xml,可以從ehcache組件包中拷貝一個,也可以自己建立一個,需要放到classpath下,一般放於/WEB-INF/classed/ehcache.xml;具體的配置文件可以網上搜一下
4.實際運用
一個網站的首頁估計是被訪問次數最多的,我們可以考慮給首頁做一個頁面緩存;
緩存策略:應該是某個固定時間之內不變的,比如說2分鍾更新一次,以應用結構page-filter-action-service--db為例。
位置:頁面緩存做到盡量靠近客戶的地方,就是在page和filter之間,這樣的優點就是第一個用戶請求後,頁面被緩存,第二個用戶在請求,走到filter這個請求就結束了,需要在走到action-service--db,好處當然是伺服器壓力大大降低和客戶端頁面響應速度加快。
首頁頁面緩存存活時間定為2分鍾,也就是參數timeToLiveSeconds(緩存的存活時間)應該設置為120,同時timeToIdleSeconds(多長時間不訪問緩存,就清楚該緩存)最好也設為2分鍾或者小於2分鍾。

接著我們來看一下SimplePageCachingFilter的配置,

<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
<filter-class>
<filter>
<filter-mapping>
<filter-name>indexCacheFilterfilter-name>
<url-pattern>*index.actionurl-pattern>
<filter-mapping>

將上述代碼加入到web.xml,那麼當打開首頁時,你會發現2分鍾才會有一堆sql語句出現在控制台,也可以調整為5分鍾,總之一切盡在掌控之中。

當然,如果你像緩存首頁的部分內容時,你需要使用這個filter,我看一下:
<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.
<filter-class>
filter>
<filter-mapping>
<filter-name>indexCacheFilterfilter-name>
<url-pattern>*/index_right.jsp<url-pattern>
<filter-mapping>

如此我們將jsp頁面通過jsp:include到其他頁面,這樣就做到了頁面局部緩存的效果,這一點貌似沒有oscache的tag好用。

此外cachefilter中還有一個特性,就是gzip,也就是緩存中的元素是被壓縮過的,如果客戶端瀏覽器支持壓縮的話,filter會直接返回壓縮過的流,這樣節省了帶寬,把解壓的工作交給了客戶端瀏覽即可,當然如果客戶端不支持gzip,那麼filter會把緩存的元素拿出來解壓後在返回給客戶端瀏覽器(大多數爬蟲是不支持gzip的,所以filter也會解壓後在返迴流)。
總之,Ehcache是一個非常輕量級的緩存實現,而且從1.2之後支持了集群,而且是hibernate默認的緩存provider,本文主要介紹Ehcahe對頁面緩存的支持,但是它的功能遠不止如此,要用好緩存,對J2ee中緩存的原理、適用范圍、適用場景等等都需要比較深刻的理解,這樣才能用好用對緩存。

為了大家通過實際例子加深了解與場景運用,在奉獻一個實例:
*在Spring中運用EhCache
適用任意一個現有開源CacheFramework,要求可以Cache系統中service或者DAO層的get/find等方法返回結果,如果數據更新(適用了Create/update/delete),則刷新cache中相應的內容。
根據需求,計劃適用SpringAOP+enCache來實現這個功能,採用ehCache原因之一就是Spring提供了enCache的支持,至於為何僅僅支持ehcache而不支持oscache和jbosscache就無從得知了。
AOP少不了攔截器,先創建一個實現了MethodInterceptor介面的攔截器,用來攔截Service/DAO的方法調用,攔截到方法後,搜索該方法的結果在cache中是否存在,如果存在,返回cache中結果,如果不存在返回資料庫查詢結果,並將結果返回到緩存。
,InitializingBean
{
privatestaticfinalLoglogger=LogFactory.getLog(MethodCacheInterceptor.class);
privateCachecache;
publicvoidsetCache(Cachecache){
this.cache=cache;
}
publicMethodCacheInterceptor(){
super();
}
/**
*攔截Service/DAO的方法,並查找該結果是否存在,如果存在就返回cache中的值,
*否則,返回資料庫查詢結果,並將查詢結果放入cache
*/
publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{
StringtargetName=invocation.getThis().getClass().getName();
StringmethodName=invocation.getMethod().getName();
Object[]arguments=invocation.getArguments();
Objectresult;
logger.debug("Findobjectfromcacheis"+cache.getName());
StringcacheKey=getCacheKey(targetName,methodName,arguments);
Elementelement=cache.get(cacheKey);
Page13of26
if(element==null){
logger.debug("Holpmethod,Getmethodresultandcreatecache........!");
result=invocation.proceed();
element=newElement(cacheKey,(Serializable)result);
cache.put(element);
}
returnelement.getValue();
}
/**
*獲得cachekey的方法,cachekey是Cache中一個Element的唯一標識
*cachekey包括包名+類名+方法名,如com.co.cache.service.UserServiceImpl.getAllUser
*/
privateStringgetCacheKey(StringtargetName,StringmethodName,Object[]arguments){
StringBuffersb=newStringBuffer();
sb.append(targetName).append(".").append(methodName);
if((arguments!=null)&&(arguments.length!=0)){
for(inti=0;i<arguments.length;i++){
sb.append(".").append(arguments[i]);
}
}
returnsb.toString();
}
/**
*implementInitializingBean,檢查cache是否為空
*/
publicvoidafterPropertiesSet()throwsException{
Assert.notNull(cache,"Needacache.PleaseusesetCache(Cache)createit.");
}
}

上面的代碼可以看到,在方法invoke中,完成了搜索cache/新建cache的功能
隨後,再建立一個攔截器MethodCacheAfterAdvice,作用是在用戶進行create/update/delete操作時來刷新、remove相關cache內容,這個攔截器需要實現AfterRetruningAdvice介面,將會在所攔截的方法執行後執行在afterReturning(objectarg0,Methodarg1,Object[]arg2,objectarg3)方法中所預定的操作

,InitializingBean
{
privatestaticfinalLoglogger=LogFactory.getLog(MethodCacheAfterAdvice.class);
privateCachecache;
Page15of26
publicvoidsetCache(Cachecache){
this.cache=cache;
}
publicMethodCacheAfterAdvice(){
super();
}
publicvoidafterReturning(Objectarg0,Methodarg1,Object[]arg2,Objectarg3)throws
Throwable{
StringclassName=arg3.getClass().getName();
Listlist=cache.getKeys();
for(inti=0;i<list.size();i++){
StringcacheKey=String.valueOf(list.get(i));
if(cacheKey.startsWith(className)){
cache.remove(cacheKey);
logger.debug("removecache"+cacheKey);
}
}
}
publicvoidafterPropertiesSet()throwsException{
Assert.notNull(cache,"Needacache.PleaseusesetCache(Cache)createit.");
}
}

該方法獲取目標class的全名,如:com.co.cache.test.TestServiceImpl,然後循環cache的keylist,刷新/removecache中所有和該class相關的element。

接著就是配置encache的屬性,如最大緩存數量、cache刷新的時間等等。
<ehcache>
<diskStorepath="c:\myapp\cache"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cachename="DEFAULT_CACHE"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300000"
timeToLiveSeconds="600000"
overflowToDisk="true"
/>
</ehcache>

這里需要注意的是defaultCache定義了一個默認的cache,這個Cache不能刪除,否則會拋出Nodefaultcacheisconfigured異常。另外由於使用攔截器來刷新Cache內容,因此在定義cache生命周期時可以定義較大的數值,timeToIdleSeconds="30000000",timeToLiveSeconds="6000000",好像還不夠大?

然後再將Cache和兩個攔截器配置到Spring的配置文件cache.xml中即可,需要創建兩個「切入點」,分別用於攔截不同方法名的方法。在配置application.xml並且導入cache.xml。這樣一個簡單的Spring+Encache框架就搭建完成。

熱點內容
android區域網視頻 發布:2024-10-08 18:35:29 瀏覽:691
java訪問私有變數 發布:2024-10-08 18:34:50 瀏覽:84
vivo鎖屏壁紙緩存在哪 發布:2024-10-08 18:34:49 瀏覽:535
insta360oner配多大的存儲卡 發布:2024-10-08 18:34:40 瀏覽:212
csgo和永劫無間哪個配置要求高 發布:2024-10-08 18:20:47 瀏覽:48
43資料庫 發布:2024-10-08 18:19:20 瀏覽:816
svn伺服器不能訪問 發布:2024-10-08 18:18:36 瀏覽:984
壓縮面膜多少錢 發布:2024-10-08 18:18:01 瀏覽:539
徐州少兒編程培訓機構 發布:2024-10-08 17:52:29 瀏覽:389
c語言常用函數大全 發布:2024-10-08 17:46:33 瀏覽:410