欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Hibernate二級緩存攻略
作者:AreYouOk
文檔來(lái)自:http://forum.javaeye.com/viewtopic.php?t=18904
很多人對二級緩存都不太了解,或者是有錯誤的認識,我一直想寫(xiě)一篇文章介紹一下hibernate的二級緩存的,今天終于忍不住了。
我的經(jīng)驗主要來(lái)自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。

hibernate的session提供了一級緩存,每個(gè)session,對同一個(gè)id進(jìn)行兩次load,不會(huì )發(fā)送兩條sql給數據庫,但是session關(guān)閉的時(shí)候,一級緩存就失效了。

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


緩存可以簡(jiǎn)單的看成一個(gè)Map,通過(guò)key在緩存里面找value。

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

查詢(xún)緩存
首先需要配置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);//激活查詢(xún)緩存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選
第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個(gè)查詢(xún)緩存做一個(gè)單獨的配置,使用setCacheRegion來(lái)做這個(gè)指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不設置cacheRegion的話(huà),那么會(huì )使用上面提到的標準查詢(xún)緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

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

另外,如果hql查詢(xún)包含select字句,那么查詢(xún)緩存里面的value就是整個(gè)結果集了。

當hibernate更新數據庫的時(shí)候,它怎么知道更新哪些查詢(xún)緩存呢?
hibernate在一個(gè)地方維護每個(gè)表的最后更新時(shí)間,其實(shí)也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
當通過(guò)hibernate更新的時(shí)候,hibernate會(huì )知道這次更新影響了哪些表。然后它更新這些表的最后更新時(shí)間。每個(gè)緩存都有一個(gè)生成時(shí)間和這個(gè)緩存所查詢(xún)的表,當hibernate查詢(xún)一個(gè)緩存是否存在的時(shí)候,如果緩存存在,它還要取出緩存的生成時(shí)間和這個(gè)緩存所查詢(xún)的表,然后去查找這些表的最后更新時(shí)間,如果有一個(gè)表在生成時(shí)間后更新過(guò)了,那么這個(gè)緩存是無(wú)效的。
可以看出,只要更新過(guò)一個(gè)表,那么凡是涉及到這個(gè)表的查詢(xún)緩存就失效了,因此查詢(xún)緩存的命中率可能會(huì )比較低。

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的緩存和前面查詢(xún)緩存的list一樣,也是只保持一串id,但它不會(huì )因為這個(gè)表更新過(guò)就失效,一個(gè)collection緩存僅在這個(gè)collection里面的元素有增刪時(shí)才失效。
這樣有一個(gè)問(wèn)題,如果你的collection是根據某個(gè)字段排序的,當其中一個(gè)元素更新了該字段時(shí),導致順序改變時(shí),collection緩存里面的順序沒(méi)有做更新。

緩存策略
只讀緩存(read-only):沒(méi)有什么好說(shuō)的
讀/寫(xiě)緩存(read-write):程序可能要的更新數據
不嚴格的讀/寫(xiě)緩存(nonstrict-read-write):需要更新數據,但是兩個(gè)事務(wù)更新同一條記錄的可能性很小,性能比讀寫(xiě)緩存好
事務(wù)緩存(transactional):緩存支持事務(wù),發(fā)生異常的時(shí)候,緩存也能夠回滾,只支持jta環(huán)境,這個(gè)我沒(méi)有怎么研究過(guò)

讀寫(xiě)緩存和不嚴格讀寫(xiě)緩存在實(shí)現上的區別在于,讀寫(xiě)緩存更新緩存的時(shí)候會(huì )把緩存里面的數據換成一個(gè)鎖,其他事務(wù)如果去取相應的緩存數據,發(fā)現被鎖住了,然后就直接取數據庫查詢(xún)。
在hibernate2.1的ehcache實(shí)現中,如果鎖住部分緩存的事務(wù)發(fā)生了異常,那么緩存會(huì )一直被鎖住,直到60秒后超時(shí)。
不嚴格讀寫(xiě)緩存不鎖定緩存中的數據。


使用二級緩存的前置條件
你的hibernate程序對數據庫有獨占的寫(xiě)訪(fǎng)問(wèn)權,其他的進(jìn)程更新了數據庫,hibernate是不可能知道的。你操作數據庫必需直接通過(guò)hibernate,如果你調用存儲過(guò)程,或者自己使用jdbc更新數據庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪除是不更新二級緩存的,但是據說(shuō)3.1已經(jīng)解決了這個(gè)問(wèn)題。
這個(gè)限制相當的棘手,有時(shí)候hibernate做批量更新、刪除很慢,但是你卻不能自己寫(xiě)jdbc來(lái)優(yōu)化,很郁悶吧。
SessionFactory也提供了移除緩存的方法,你一定要自己寫(xiě)一些JDBC的話(huà),可以調用這些方法移除緩存,這些方法是:
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.
不過(guò)我不建議這樣做,因為這樣很難維護。比如你現在用JDBC批量更新了某個(gè)表,有3個(gè)查詢(xún)緩存會(huì )用到這個(gè)表,用evictQueries(String cacheRegion)移除了3個(gè)查詢(xún)緩存,然后用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過(guò)哪天你添加了一個(gè)相關(guān)查詢(xún)緩存,可能會(huì )忘記更新這里的移除代碼。如果你的jdbc代碼到處都是,在你添加一個(gè)查詢(xún)緩存的時(shí)候,還知道其他什么地方也要做相應的改動(dòng)嗎?

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

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


終于寫(xiě)完了,好累……

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Hibernate緩存何時(shí)使用和如何使用
hibernate 緩存清除
hibernate 緩存
Hibernate二級緩存【轉】新理解
Hibernate一級緩存和二級緩存
Hibernate4之二級緩存
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久