Thinking

          快樂編程,開心生活
          posts - 21, comments - 27, trackbacks - 0, articles - -5
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Cache的層次

          Posted on 2007-02-06 17:31 lixw 閱讀(637) 評論(0)  編輯  收藏

          1、查詢緩存

          ? 首先需要配置hibernate.cache.use_query_cache=true

          如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了

          ?1?<cache?name="net.sf.hibernate.cache.StandardQueryCache"
          ?2?
          ?3?maxElementsInMemory="50"?eternal="false"?timeToIdleSeconds="3600"
          ?4?
          ?5?timeToLiveSeconds="7200"?overflowToDisk="true"/>
          ?6?
          ?7?<cache?name="net.sf.hibernate.cache.UpdateTimestampsCache"
          ?8?
          ?9?maxElementsInMemory="5000"?eternal="true"?overflowToDisk="true"/>
          10?
          11?

          ? 然后

          query.setCacheable(true);//激活查詢緩存

          query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選

          第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個查詢緩存做一個單獨的配置,

          使用setCacheRegion來做這個指定,需要在ehcache.xml里面配置它:

          1 < cache? name ="myCacheRegion" ?maxElementsInMemory ="10" ?eternal ="false"
          2
          3 timeToIdleSeconds ="3600" ?timeToLiveSeconds ="7200" ?overflowToDisk ="true" ? />
          4
          5


          如果省略第二行,不設置cacheRegion的話,那么會使用上面提到的標準查詢緩存的配置,也就是

          net.sf.hibernate.cache.StandardQueryCache

          ? 問題:當hibernate更新數據庫的時候,它怎么知道更新哪些查詢緩存呢?

          ??? hibernate在一個地方維護每個表的最后更新時間,其實也就是放在上面

          net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。

          當通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時間和這個緩存所查詢的表,當hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

          ? 注意:

          ??? 放入緩存中的key是查詢的語句,value是查詢之后得到的結果集的id列表。

          表面看來這樣的方案似乎能解決hql利用緩存的問題,但是需要注意的是,構成key的是:

          hql生成的sql、sql的參數、排序、分頁信息等。也就是說如果你的hql有小小的差異,

          比如第一條hql取1-50條數據,第二條hql取20-60條數據,那么hibernate會認為這是兩個

          完全不同的key,無法重復利用緩存。因此利用率也不高。

          ?? 查詢緩存必須配合二級緩存一起使用,否則極易出現1+N的情況

          ?? 如果不設置"查詢緩存",那么hibernate只會緩存使用load()方法獲得的單個持久化對象,

          如果想緩存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法

          獲得的數據結果集的話,就需要設置hibernate.cache.use_query_cache true才行,如果需要"查詢緩存",需要在使用Query或Criteria()時設置其setCacheable(true);屬性。?
          2、Collection緩存

          ? 需要在hbm的collection里面設置

          < cache? usage ="read-write" />

          假如class是Cat,collection叫children,那么ehcache里面配置

          1 < cache? name ="com.xxx.pojo.Cat.children"
          2
          3 maxElementsInMemory ="20" ?eternal ="false" ?timeToIdleSeconds ="3600"
          4
          5 timeToLiveSeconds ="7200"
          6
          7 overflowToDisk ="true" ? />
          8

          Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就

          失效,一個collection緩存僅在這個collection里面的元素有增刪時才失效。

          這樣有一個問題,如果你的collection是根據某個字段排序的,當其中一個元素更新了該字段時,

          導致順序改變時,collection緩存里面的順序沒有做更新?
          3、Class緩存(也稱二級緩存)

          ?? 可由Hibernate提供的二級緩存實現,它存在于SessionFactory級別,

          緩存結構可以看作是一個hash table,key是數據庫記錄的id,value是id對應的pojo對象。

          當用戶根據id查詢對象的時候(load、iterator方法),會首先在緩存中查找,

          如果沒有找到再發起數據庫查詢。但是如果使用hql發起查詢(find, query方法)

          則不會利用二級緩存,而是直接從數據庫獲得數據,但是它會把得到的數據放到二級緩存備用。也就是說,基于hql的查詢,對二級緩存是只寫不讀的。?
          在hibernate.cfg.xml配置:

          < property? name ="hibernate.cache.provider_class" >

          ???????org.hibernate.cache.EhCacheProvider

          </ property >

          hibernate3支持

          Hashtable Cache(org.hibernate.cache.HashtableCacheProvider)

          EhCache(org.hibernate.cache.EhCacheProvider)

          OSCache(org.hibernate.cache.OSCacheProvider)

          SwarmCache(org.hibernate.cache.SwarmCacheProvider)

          JBossCache(org.hibernate.cache.TreeCacheProvider)

          在相應的POJO配置文件中增加:

          <!--

          指定緩存同步策略:

          read-write???????????????????????????讀寫型

          nonstrict-read-write?????????????非嚴格讀寫型

          read-only?????????????????????????? ?只讀型

          transactional??????????????????????? 事務型

          -->

          <cache usage="read-write"/>?

          Cache read-only nonstrict-read-write read-write transactional
          EhCache Yes Yes Yes No
          OSCache Yes Yes Yes No
          SwarmCache Yes Yes No No
          TreeCache Yes No No Yes

          ?????對于一條記錄,也就是一個PO來說,是根據ID來找的,緩存的key就是ID,value是POJO。無論

          list,load還是iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate

          會先取數據庫select id出來,然后一個id一個id的load,如果在緩存里面有,就從緩存取,沒有

          的話就去數據庫load。

          ?? 當某個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查詢的結

          果緩存,就要用到查詢緩存了。?
          ? 注意:

          ?? 對于one-to-many的關聯關系,如果對one應用緩存,則應同時對many應用。

          ?? 二級緩存的失效機制由hibernate控制,當某條數據被修改之后,hibernate會根據它的id去做

          緩存失效操作。基于此機制,如果數據表不是被hibernate獨占,那么二級緩存無法得到有效控制

          ?? hibernate 3.0在做批量修改、批量更新的時候,是不會同步更新二級緩存的

          ?? 查詢緩存和二級緩存是有關聯關系的,他們不是完全獨立的兩套東西。假如一個查詢條件hql_1

          ,第一次被執行的時候,它會從數據庫取得數據,然后把查詢條件作為key,把返回數據的所有id

          列表作為value(請注意僅僅是id)放到查詢緩存中,同時整個結果集放到二級緩存,key是id,

          value是pojo對象。當你再次執行hql_1,它會從緩存中得到id列表,然后根據這些列表一個一個的

          到二級緩存里面去找pojo對象,如果找不到就向數據庫發起查詢。也就是說,如果二級緩存配置了

          超時時間,就有可能出現查詢緩存命中了,獲得了id列表,但是class里面相應的pojo已經因為超

          時被失效,hibernate就會根據id清單,一個一個的去向數據庫查詢,有多少個id,就執行多少個

          sql。該情況將導致性能下降嚴重。

          ?? 查詢緩存的失效機制也由hibernate控制,數據進入緩存時會有一個timestamp,它和數據表的

          timestamp對應。當hibernate環境內發生save、update等操作時,會更新被操作數據表的

          timestamp。用戶在獲取緩存的時候,一旦命中就會檢查它的timestamp是否和數據表的timestamp

          匹配,如果不,緩存會被失效。因此查詢緩存的失效控制是以數據表為粒度的,只要數據表中任何

          一條記錄發生一點修改,整個表相關的所有查詢緩存就都無效了。因此查詢緩存的命中率可能會很

          低。?
          4、對方法的緩存

          ? 對于調用頻率較高的查詢類方法,我們希望緩存方法結果

          在spring中可利用攔截器(Interceptor)實現,可能如下面的配置:

          ?1 < beans >
          ?2
          ?3 ???? < bean? id ="cacheInterceptor"
          ?4
          ?5 class ="org.springframework.aop.interceptor.cache.OSCacheInterceptor" >
          ?6
          ?7 ??????? <! -?默認刷新時間(秒)- >
          ?8
          ?9 ??????? < property? name ="defaultRefreshPeriod" >
          10
          11 ??????????? < value > 60 </ value >
          12
          13 ??????? </ property >
          14
          15 ??????? < property? name ="identifiers" >
          16
          17 ??????????? < props >
          18
          19 ?????????????? < prop? key ="java.util.Map" > toString </ prop >
          20
          21 ??????????? </ props >
          22
          23 ??????? </ property >
          24
          25 ???? </ bean >
          26
          27 ???? <! -?正則表達式匹配?- >
          28
          29 ???? < bean? id ="searcherAdvisor"
          30
          31 class ="org.springframework.aop.support.RegexpMethodPointcutAdvisor" >
          32
          33 ??????? < property? name ="advice" >
          34
          35 ??????????? < ref? local ="cacheInterceptor" ? />
          36
          37 ??????? </ property >
          38
          39 ??????? < property? name ="patterns" >
          40
          41 ??????????? < list >
          42
          43 ?????????????? < value > .get. </ value >
          44
          45 ??????????? </ list >
          46
          47 ??????? </ property >
          48
          49 ???? </ bean >
          50
          51 ???? <! -?自動代理?- >
          52
          53 ???? < bean? id ="proxyCreator1"
          54
          55 class ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
          56
          57 ??????? < property? name ="beanNames" >
          58
          59 ?????????? <!-- ?需截獲方法的bean列表? -->
          60
          61 ??????????? < list >
          62
          63 ?????????????? < value > commonSelect </ value >
          64
          65 ??????????? </ list >
          66
          67 ??????? </ property >
          68
          69 ??????? < property? name ="interceptorNames" >
          70
          71 ?????????? <!-- ?截獲器列表? -->
          72
          73 ??????????? < list >
          74
          75 ?????????????? < value > searcherAdvisor </ value >
          76
          77 ??????????? </ list >
          78
          79 ??????? </ property >
          80
          81 ???? </ bean >
          82
          83 < beans >
          84
          85

          ?這里通過自動代理創建bean,并指定作用其上的interceptor列表,在commonSelect存在searchAdvisor,

          而searchAdvisor對匹配*get*模式的方法調用將通過cacheInterceptor進行處理。


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 永新县| 漯河市| 噶尔县| 博野县| 紫云| 阳山县| 大洼县| 平度市| 阿合奇县| 临沂市| 西和县| 平和县| 琼海市| 图片| 武安市| 通化县| 互助| 龙胜| 弥勒县| 隆安县| 波密县| 绵阳市| 昌图县| 铜川市| 黑水县| 肇源县| 浮山县| 永兴县| 根河市| 广东省| 屯留县| 泌阳县| 屏东市| 栾川县| 平塘县| 乌审旗| 九江市| 文登市| 临泽县| 突泉县| 兴安盟|