笑看風(fēng)云

          一切從頭開始
          posts - 28, comments - 1, trackbacks - 0, articles - 2

          Hibernate3緩存管理

          Posted on 2009-01-09 15:58 笑看風(fēng)云 閱讀(255) 評論(0)  編輯  收藏 所屬分類: hibernate
          Hibernate緩存管理
                                                                
          1.    Cache簡介:
          緩存(Cache )是計(jì)算機(jī)領(lǐng)域非常通用的概念。它介于應(yīng)用程序和永久性數(shù)據(jù)存儲源(如硬盤上的文件或者數(shù)據(jù)庫)之間,其作用是降低應(yīng)用程序直接讀寫永久性數(shù)據(jù)存儲源的頻率,從而提高應(yīng)用的運(yùn)行性能。緩存中的數(shù)據(jù)是數(shù)據(jù)存儲源中數(shù)據(jù)的拷貝,應(yīng)用程序在運(yùn)行時(shí)直接讀寫緩存中的數(shù)據(jù),只在某些特定時(shí)刻按照緩存中的數(shù)據(jù)來同步更新數(shù)據(jù)存儲源。
          緩存的物理介質(zhì)通常是內(nèi)存,而永久性數(shù)據(jù)存儲源的物理介質(zhì)通常是硬盤或磁盤,應(yīng)用程序讀寫內(nèi)在的速度顯然比讀寫硬盤的速度快,如果緩存中存放的數(shù)據(jù)量非常大,也會用硬盤作為緩存的物理介質(zhì)。
          緩存的實(shí)現(xiàn)不僅需要作為物理介質(zhì)的硬件,同時(shí)還需要用于管理緩存的并發(fā)訪問和過期等策略的軟件。因此,緩存是通過軟件和硬件共同實(shí)現(xiàn)的。
          1.1.    持久化層的緩存的范圍
          緩存的范圍決定了緩存的生命周期以及可以被誰訪問。緩存的范圍分為三類。
          1) 事務(wù)范圍:緩存只能被當(dāng)前事務(wù)訪問。緩存的生命周期依賴于事務(wù)的生命周期,當(dāng)事務(wù)結(jié)束時(shí),緩存也就結(jié)束生命周期。在此范圍下,緩存的介質(zhì)是內(nèi)存。事務(wù)可以是數(shù)據(jù)庫事務(wù)或者應(yīng)用事務(wù),每個(gè)事務(wù)都有獨(dú)自的緩存,緩存內(nèi)的數(shù)據(jù)通常采用相互關(guān)聯(lián)的對象形式。
          2) 進(jìn)程范圍:緩存被進(jìn)程內(nèi)的所有事務(wù)共享。這些事務(wù)有可能是并發(fā)訪問緩存,因此必須對緩存采取必要的事務(wù)隔離機(jī)制。緩存的生命周期依賴于進(jìn)程的生命周期,進(jìn)程結(jié)束時(shí),緩存也就結(jié)束了生命周期。進(jìn)程范圍的緩存可能會存放大量的數(shù)據(jù),所以存放的介質(zhì)可以是內(nèi)存或硬盤。緩存內(nèi)的數(shù)據(jù)既可以是相互關(guān)聯(lián)的對象形式也可以是對象的松散數(shù)據(jù)形式。松散的對象數(shù)據(jù)形式有點(diǎn)類似于對象的序列化數(shù)據(jù),但是對象分解為松散的算法比對象序列化的算法要求更快。
          3) 集群范圍:在集群環(huán)境中,緩存被一個(gè)機(jī)器或者多個(gè)機(jī)器的進(jìn)程共享。緩存中的數(shù)據(jù)被復(fù)制到集群環(huán)境中的每個(gè)進(jìn)程節(jié)點(diǎn),進(jìn)程間通過遠(yuǎn)程通信來保證緩存中的數(shù)據(jù)的一致性,緩存中的數(shù)據(jù)通常采用對象的松散數(shù)據(jù)形式。
          對大多數(shù)應(yīng)用來說,應(yīng)該慎重地考慮是否需要使用集群范圍的緩存,因?yàn)樵L問的速度不一定會比直接訪問數(shù)據(jù)庫數(shù)據(jù)的速度快多少。
           
          持久化層可以提供多種范圍的緩存。如果在事務(wù)范圍的緩存中沒有查到相應(yīng)的數(shù)據(jù),還可以到進(jìn)程范圍或集群范圍的緩存內(nèi)查詢,如果還是沒有查到,那么只有到數(shù)據(jù)庫中查詢。事務(wù)范圍的緩存是持久化層的第一級緩存,通常它是必需的;進(jìn)程范圍或集群范圍的緩存是持久化層的第二級緩存,通常是可選的。
          1.2.    持久化層的緩存的并發(fā)訪問策略
          當(dāng)多個(gè)并發(fā)的事務(wù)同時(shí)訪問持久化層的緩存的相同數(shù)據(jù)時(shí),會引起并發(fā)問題,必須采用必要的事務(wù)隔離措施。
          在進(jìn)程范圍或集群范圍的緩存,即第二級緩存,會出現(xiàn)并發(fā)問題。因此可以設(shè)定以下四種類型的并發(fā)訪問策略,每一種策略對應(yīng)一種事務(wù)隔離級別。
          1) 事務(wù)型(Transactional)策略:僅僅在受管理環(huán)境中適用。它提供了Repeatable Read事務(wù)隔離級別。對于經(jīng)常被讀但很少修改的數(shù)據(jù),可以采用這種隔離類型,因?yàn)樗梢苑乐古K讀和不可重復(fù)讀這類的并發(fā)問題。
          2) 讀寫型(read-write)策略:提供了Read Committed事務(wù)隔離級別。僅僅在非集群的環(huán)境中適用。對于經(jīng)常被讀但很少修改的數(shù)據(jù),可以采用這種隔離類型,因?yàn)樗梢苑乐古K讀這類的并發(fā)問題。
          3) 非嚴(yán)格讀寫型(nonstrict-read-write)策略:不保證緩存與數(shù)據(jù)庫中數(shù)據(jù)的一致性。如果存在兩個(gè)事務(wù)同時(shí)訪問緩存中相同數(shù)據(jù)的可能,必須為該數(shù)據(jù)配置一個(gè)很短的數(shù)據(jù)過期時(shí)間,從而盡量避免臟讀。對于極少被修改,并且允許偶爾臟讀的數(shù)據(jù),可以采用這種并發(fā)訪問策略。
          4) 只讀型策略(read-only):對于從來不會修改的數(shù)據(jù),如參考數(shù)據(jù),可以使用這種并發(fā)訪問策略。
          事務(wù)型并發(fā)訪問策略是事務(wù)隔離級別最高,只讀型的隔離級別最低。事務(wù)隔離級別越高,并發(fā)性能就越低。
          2.    Hibernate中的緩存:
          Hibernate中提供了兩級Cache,第一級別的緩存是Session級別的緩存,它是屬于事務(wù)范圍的緩存。這一級別的緩存由hibernate管理的,一般情況下無需進(jìn)行干預(yù);第二級別的緩存是SessionFactory級別的緩存,它是屬于進(jìn)程范圍或群集范圍的緩存。這一級別的緩存可以進(jìn)行配置和更改,并且可以動態(tài)加載和卸載。
          Hibernate還為查詢結(jié)果提供了一個(gè)查詢緩存,它依賴于第二級緩存。
          2.1.    一級緩存和二級緩存的比較:
            第一級緩存 第二級緩存 
          存放數(shù)據(jù)的形式 相互關(guān)聯(lián)的持久化對象 對象的散裝數(shù)據(jù) 
          緩存的范圍 事務(wù)范圍,每個(gè)事務(wù)都有單獨(dú)的第一級緩存 進(jìn)程范圍或集群范圍,緩存被同一個(gè)進(jìn)程或集群范圍內(nèi)的所有事務(wù)共享 
          并發(fā)訪問策略 由于每個(gè)事務(wù)都擁有單獨(dú)的第一級緩存,不會出現(xiàn)并發(fā)問題,無需提供并發(fā)訪問策略 由于多個(gè)事務(wù)會同時(shí)訪問第二級緩存中相同數(shù)據(jù),因此必須提供適當(dāng)?shù)牟l(fā)訪問策略,來保證特定的事務(wù)隔離級別 
          數(shù)據(jù)過期策略 沒有提供數(shù)據(jù)過期策略。處于一級緩存中的對象永遠(yuǎn)不會過期,除非應(yīng)用程序顯式清空緩存或者清除特定的對象 必須提供數(shù)據(jù)過期策略,如基于內(nèi)存的緩存中的對象的最大數(shù)目,允許對象處于緩存中的最長時(shí)間,以及允許對象處于緩存中的最長空閑時(shí)間 
          物理存儲介質(zhì) 內(nèi)存 內(nèi)存和硬盤。對象的散裝數(shù)據(jù)首先存放在基于內(nèi)在的緩存中,當(dāng)內(nèi)存中對象的數(shù)目達(dá)到數(shù)據(jù)過期策略中指定上限時(shí),就會把其余的對象寫入基于硬盤的緩存中。 
          緩存的軟件實(shí)現(xiàn) 在Hibernate的Session的實(shí)現(xiàn)中包含了緩存的實(shí)現(xiàn) 由第三方提供,Hibernate僅提供了緩存適配器(CacheProvider)。用于把特定的緩存插件集成到Hibernate中。 
          啟用緩存的方式 只要應(yīng)用程序通過Session接口來執(zhí)行保存、更新、刪除、加載和查詢數(shù)據(jù)庫數(shù)據(jù)的操作,Hibernate就會啟用第一級緩存,把數(shù)據(jù)庫中的數(shù)據(jù)以對象的形式拷貝到緩存中,對于批量更新和批量刪除操作,如果不希望啟用第一級緩存,可以繞過Hibernate API,直接通過JDBC API來執(zhí)行指操作。 用戶可以在單個(gè)類或類的單個(gè)集合的粒度上配置第二級緩存。如果類的實(shí)例被經(jīng)常讀但很少被修改,就可以考慮使用第二級緩存。只有為某個(gè)類或集合配置了第二級緩存,Hibernate在運(yùn)行時(shí)才會把它的實(shí)例加入到第二級緩存中。 
          用戶管理緩存的方式 第一級緩存的物理介質(zhì)為內(nèi)存,由于內(nèi)存容量有限,必須通過恰當(dāng)?shù)臋z索策略和檢索方式來限制加載對象的數(shù)目。Session的evit()方法可以顯式清空緩存中特定對象,但這種方法不值得推薦。 第二級緩存的物理介質(zhì)可以是內(nèi)存和硬盤,因此第二級緩存可以存放大量的數(shù)據(jù),數(shù)據(jù)過期策略的maxElementsInMemory屬性值可以控制內(nèi)存中的對象數(shù)目。管理第二級緩存主要包括兩個(gè)方面:選擇需要使用第二級緩存的持久類,設(shè)置合適的并發(fā)訪問策略:選擇緩存適配器,設(shè)置合適的數(shù)據(jù)過期策略。 

           
          2.2.    一級緩存的管理:
          當(dāng)應(yīng)用程序調(diào)用Session的save()、update()、savaeOrUpdate()、get()或load(),以及調(diào)用查詢接口的list()、iterate()或filter()方法時(shí),如果在Session緩存中還不存在相應(yīng)的對象,Hibernate就會把該對象加入到第一級緩存中。當(dāng)清理緩存時(shí),Hibernate會根據(jù)緩存中對象的狀態(tài)變化來同步更新數(shù)據(jù)庫。
          Session為應(yīng)用程序提供了兩個(gè)管理緩存的方法:
          evict(Object obj):從緩存中清除參數(shù)指定的持久化對象。
          clear():清空緩存中所有持久化對象。
          2.3.    二級緩存的管理:
          2.3.1.      Hibernate的二級緩存策略的一般過程如下:
          1) 條件查詢的時(shí)候,總是發(fā)出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數(shù)據(jù)庫,一次獲得所有的數(shù)據(jù)對象。 
          2) 把獲得的所有數(shù)據(jù)對象根據(jù)ID放入到第二級緩存中。 
          3) 當(dāng)Hibernate根據(jù)ID訪問數(shù)據(jù)對象的時(shí)候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那么從二級緩存中查;查不到,再查詢數(shù)據(jù)庫,把結(jié)果按照ID放入到緩存。 
          4) 刪除、更新、增加數(shù)據(jù)的時(shí)候,同時(shí)更新緩存。
            Hibernate的二級緩存策略,是針對于ID查詢的緩存策略,對于條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache。
          2.3.2.      什么樣的數(shù)據(jù)適合存放到第二級緩存中?
          1 很少被修改的數(shù)據(jù)
          2 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)
          3 不會被并發(fā)訪問的數(shù)據(jù)
          4 參考數(shù)據(jù),指的是供應(yīng)用參考的常量數(shù)據(jù),它的實(shí)例數(shù)目有限,它的實(shí)例會被許多其他類的實(shí)例引用,實(shí)例極少或者從來不會被修改。
          2.3.3.      不適合存放到第二級緩存的數(shù)據(jù)?
          1 經(jīng)常被修改的數(shù)據(jù)
          2 財(cái)務(wù)數(shù)據(jù),絕對不允許出現(xiàn)并發(fā)
          3 與其他應(yīng)用共享的數(shù)據(jù)。
           
          2.3.4.      常用的緩存插件
          Hibernater 的二級緩存是一個(gè)插件,下面是幾種常用的緩存插件:
          l EhCache:可作為進(jìn)程范圍的緩存,存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤,對Hibernate的查詢緩存提供了支持。
          l OSCache:可作為進(jìn)程范圍的緩存,存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤,提供了豐富的緩存數(shù)據(jù)過期策略,對Hibernate的查詢緩存提供了支持。
          l SwarmCache:可作為群集范圍內(nèi)的緩存,但不支持Hibernate的查詢緩存。
          l JBossCache:可作為群集范圍內(nèi)的緩存,支持事務(wù)型并發(fā)訪問策略,對Hibernate的查詢緩存提供了支持。
           
          2.3.5.      配置二級緩存的主要步驟:
          1)      選擇需要使用二級緩存的持久化類,設(shè)置它的命名緩存的并發(fā)訪問策略。這是最值得認(rèn)真考慮的步驟。
          2)      選擇合適的緩存插件,然后編輯該插件的配置文件。
          2.4.    使用EhCache配置二級緩存:
          2.4.1.      配置準(zhǔn)備:
          1)      把ehcache-1.2.3.jar加入到當(dāng)前應(yīng)用的classpath中。
          2)      在hibernate.cfg.xml文件中加入EhCache緩存插件的提供類。
          <!--配置緩存插件 -->
          <property name="hibernate.cache.provider_class">
              org.hibernate.cache.EhCacheProvider
          </property> 

          3)      挎貝ehcache.xml文件到類路徑(項(xiàng)目工程的src目錄下),這個(gè)文件在Hibernate安裝目錄的etc下。
          2.4.2.      配置步驟:
          Hibernate允許在類和集合的粒度上設(shè)置第二級緩存。在映射文件中,
          <class><set>元素都有一個(gè)<cache>子元素,這個(gè)子元素用來配置二級緩存。
          示例:以category(產(chǎn)品類別)和product(產(chǎn)品)的映射為例:
          1)      修改要配置緩存的那個(gè)持久化類的對象關(guān)系映射文件:
          Category.hbm.xml
          <?xml version="1.0" encoding="utf-8"?>
          <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
           
          <hibernate-mapping>
              
          <class name="org.qiujy.domain.cachedemo.Category" table="categories">
                 
          <!
                       配置緩存,必須緊跟在class元素后面
                      對緩存中的Category對象采用讀寫型的并發(fā)訪問策略
                  
          -->
                 
          <cache usage="read-write"/>
                 
                 
          <id name="id" type="java.lang.Long">
                     
          <column name="id" />
                     
          <generator class="native" />
                 
          </id>
                 
          <!-- 配置版本號,必須緊跟在id元素后面 -->
                 
          <version name="version" column="version" type="java.lang.Long" />
                 
                 
          <property name="name" type="java.lang.String">
                     
          <column name="name" length="32" not-null="true"/>
                 
          </property>
                 
                 
          <property name="description" type="java.lang.String">
                     
          <column name="description" length="255"/>
                 
          </property>
                 
                 
          <set name="products" table="products" cascade="all" inverse="true">
                     
          <!-- Hibernate只會緩存對象的簡單屬性的值,
                 要緩存集合屬性,必須在集合元素中也加入
          <cache>子元素
                 而Hibernate僅僅是把與當(dāng)前持久對象關(guān)聯(lián)的對象的OID存放到緩存中。
          如果希望把整個(gè)關(guān)聯(lián)的對象的所有數(shù)據(jù)都存入緩存,
          則要在相應(yīng)關(guān)聯(lián)的對象的映射文件中配置
          <cache>元素
                     
          -->
                     
          <cache usage="read-write"/>
                     
                     
          <key column="categoryId" not-null="true"/>
                     
          <one-to-many class="org.qiujy.domain.cachedemo.Product"/>
                 
          </set>
                 
              
          </class>
          </hibernate-mapping>
            

          Product.hbm.xml
          <?xml version="1.0" encoding="utf-8"?>
          <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
           
          <hibernate-mapping>
              
          <class name="org.qiujy.domain.cachedemo.Product" table="products">
                 
                 
          <cache usage="read-write"/>
                 
                 
          <id name="id" type="java.lang.Long">
                     
          <column name="id" />
                     
          <generator class="native" />
                 
          </id>
                 
          <!-- 配置版本號,必須緊跟在id元素后面 -->
                 
          <version name="version" column="version" type="java.lang.Long" />
                 
                 
          <property name="name" type="java.lang.String">
                     
          <column name="name" length="32" not-null="true"/>
                 
          </property>
                 
                 
          <property name="description" type="java.lang.String">
                     
          <column name="description" length="255"/>
                 
          </property>
                 
                 
          <property name="unitCost" type="java.lang.Double">
                     
          <column name="unitCost" />
                 
          </property>
                 
                 
          <property name="pubTime" type="java.util.Date">
                     
          <column name="pubTime" not-null="true" />
                 
          </property>
                 
                 
          <many-to-one name="category" 
                          column
          ="categoryId"
                         
          class="org.qiujy.domain.cachedemo.Category"
                         cascade
          ="save-update"
                          not
          -null="true">
                  
          </many-to-one>
                 
              
          </class>
          </hibernate-mapping>
            

           
          2)      編輯ehcache.xml文件:
          <ehcache>
              
          <diskStore path="c:\\ehcache\"/> 
              
          <defaultCache 
                  maxElementsInMemory
          ="10000" 
                  eternal
          ="false" 
                  timeToIdleSeconds
          ="120" 
                  timeToLiveSeconds
          ="120" 
                  overflowToDisk
          ="true"   
                  
          />
                  
              
          <!-- 設(shè)置Category類的緩存的數(shù)據(jù)過期策略 -->
              
          <cache name="org.qiujy.domain.cachedemo.Category"
                  maxElementsInMemory
          ="100"
                  eternal
          ="true"
                  timeToIdleSeconds
          ="0"
                  timeToLiveSeconds
          ="0"
                  overflowToDisk
          ="false"
                  
          />
                  
               
          <!-- 設(shè)置Category類的products集合的緩存的數(shù)據(jù)過期策略 -->
               
          <cache name="org.qiujy.domain.cachedemo.Category.products"
                  maxElementsInMemory
          ="500"
                  eternal
          ="false"
                  timeToIdleSeconds
          ="300"
                  timeToLiveSeconds
          ="600"
                  overflowToDisk
          ="true"
                  
          />
                  
              
          <cache name="org.qiujy.domain.cachedemo.Product"
                  maxElementsInMemory
          ="500"
                  eternal
          ="false"
                  timeToIdleSeconds
          ="300"
                  timeToLiveSeconds
          ="600"
                  overflowToDisk
          ="true"
                  
          />
              
          </ehcache> 

          配置的元素說明:
          元素或?qū)傩?nbsp;描述 
          <diskStore> 設(shè)置緩存數(shù)據(jù)文件的存放目錄 
          <defaultCache> 設(shè)置緩存的默認(rèn)數(shù)據(jù)過期策略 
          <cache> 設(shè)定具體的命名緩存的數(shù)據(jù)過期策略
          每個(gè)命名緩存代表一個(gè)緩存區(qū)域,每個(gè)緩存區(qū)域有各自的數(shù)據(jù)過期策略。命名緩存機(jī)制使得用戶能夠在每個(gè)類以及類的每個(gè)集合的粒度上設(shè)置數(shù)據(jù)過期策略。 
          cache元素的屬性   
          name 設(shè)置緩存的名字,它的取值為類的全限定名或類的集合的名字 
          maxInMemory 設(shè)置基于內(nèi)存的緩存中可存放的對象最大數(shù)目 
          eternal 設(shè)置對象是否為永久的,true表示永不過期,此時(shí)將忽略timeToIdleSeconds和timeToLiveSeconds屬性;
          默認(rèn)值是false 
          timeToIdleSeconds 設(shè)置對象空閑最長時(shí)間,超過這個(gè)時(shí)間,對象過期。當(dāng)對象過期時(shí),EHCache會把它從緩存中清除。
          如果此值為0,表示對象可以無限期地處于空閑狀態(tài)。 
          timeToLiveSeconds 設(shè)置對象生存最長時(shí)間,超過這個(gè)時(shí)間,對象過期。
          如果此值為0,表示對象可以無限期地存在于緩存中。 
          overflowToDisk 設(shè)置基于內(nèi)在的緩存中的對象數(shù)目達(dá)到上限后,是否把溢出的對象寫到基于硬盤的緩存中 

           
          3)      寫一測試類:
          package org.qiujy.test.cache;
           
          import java.util.List;
           
          import org.hibernate.HibernateException;
          import org.hibernate.Session;
          import org.hibernate.Transaction;
          import org.qiujy.common.HibernateSessionFactory;
          import org.qiujy.domain.cachedemo.Product;
           
          public class TestCache {
           
                 
          public static void main(String[] args) {
                  
                        
          //test cache
                        Session session2 = HibernateSessionFactory.getSession();
                        Transaction tx2 
          =null;
                        
                        
          try
                               tx2 
          = session2.beginTransaction();
                               
                               List list 
          = session2.createQuery("from Product").list();
                               
                               
          for(int i = 0 ; i < list.size(); i++){
                                      Product prod 
          = (Product)list.get(i);
                                      System.out.println(prod.getName());
                               }

                               
                              tx2.commit();
                        }
          catch(HibernateException e){
                               
          if(tx2 != null){
                                      tx2.rollback();
                               }

                               e.printStackTrace();
                        }
          finally{
                               HibernateSessionFactory.closeSession();
                        }

                        
                        
          //-------------------
                        Session session3 = HibernateSessionFactory.getSession();
                        Transaction tx3 
          =null;
                        
                        
          try
                               tx3 
          = session3.beginTransaction();
                               
                               Product prod 
          = (Product)session3.get(Product.classnew Long(1));
                               System.out.println(
          "從cache中得到,不執(zhí)行SQL---" + prod.getName());
                            
                              tx3.commit();
                        }
          catch(HibernateException e){
                               
          if(tx3 != null){
                                      tx3.rollback();
                               }

                               e.printStackTrace();
                        }
          finally{
                               HibernateSessionFactory.closeSession();
                        }

                 }

          }
           

          首先數(shù)據(jù)庫插入1000條產(chǎn)品記錄和1條類別記錄。此1000個(gè)產(chǎn)品都屬于這一類別。然后執(zhí)行以上測試類,在Session2中查詢所有的產(chǎn)品,輸出它的產(chǎn)品名,Session2會把這些數(shù)據(jù)加載到二級緩存中,由于有1000個(gè)對象,而配置中定義內(nèi)存中只能存放500個(gè),剩下的對象就會寫到指定的磁盤目錄中緩存起來。所以在磁盤相應(yīng)位置可看到數(shù)據(jù)文件:
          2.5.    查詢緩存(Query Cache):
          對于經(jīng)常使用的查詢語句,如果啟用了查詢緩存,當(dāng)?shù)谝淮螆?zhí)行查詢語句時(shí),Hibernate會把查詢結(jié)果存放在第二緩存中。以后再次執(zhí)行該查詢語句時(shí),只需從緩存中獲得查詢結(jié)果,從而提高查詢性能。
          2.5.1.      查詢緩存適用于以下場合:
          l 在應(yīng)用程序運(yùn)行時(shí)經(jīng)常使用的查詢語句。
          l 很少對與查詢語句關(guān)聯(lián)的數(shù)據(jù)庫數(shù)據(jù)進(jìn)行插入、刪除或更新操作。
          2.5.2.      Hibernate的Query緩存策略的過程如下:
          1) Hibernate首先根據(jù)這些信息組成一個(gè)Query Key,Query Key包括條件查詢的請求一般信息:SQL, SQL需要的參數(shù),記錄范圍(起始位置rowStart,最大記錄個(gè)數(shù)maxRows),等。 
          2) Hibernate根據(jù)這個(gè)Query Key到Query緩存中查找對應(yīng)的結(jié)果列表。如果存在,那么返回這個(gè)結(jié)果列表;如果不存在,查詢數(shù)據(jù)庫,獲取結(jié)果列表,把整個(gè)結(jié)果列表根據(jù)Query Key放入到Query緩存中。 
          3) Query Key中的SQL涉及到一些表名,如果這些表的任何數(shù)據(jù)發(fā)生修改、刪除、增加等操作,這些相關(guān)的Query Key都要從緩存中清空。
          只有當(dāng)經(jīng)常使用同樣的參數(shù)進(jìn)行查詢時(shí),這才會有些用處。 
          啟用查詢緩存的步驟:
          1)      配置二級緩存:
          Hibernate提供了三種和查詢相關(guān)的緩存區(qū)域:
          l 默認(rèn)的查詢緩存區(qū)域:org.hibernate.cache.StandardQueryCache
          l 用戶自定義的查詢緩存區(qū)域:
          l 時(shí)間戳緩存區(qū)域:org.hibernate.cache.UpdateTimestampCache
          默認(rèn)的查詢緩存區(qū)域以及用戶自定義的查詢緩存區(qū)域都用于存放查詢結(jié)果。而時(shí)間戳緩存區(qū)域存放了對與查詢結(jié)果相關(guān)的表進(jìn)行插入、更新或刪除操作的時(shí)間戳。Hibernate通過時(shí)間戳緩存區(qū)域來判斷被緩存的查詢結(jié)果是否過期。所以,當(dāng)應(yīng)用程序?qū)?shù)據(jù)庫的相關(guān)數(shù)據(jù)做了修改,Hibernate會自動刷新緩存的查詢結(jié)果。但是如果其他應(yīng)用程序?qū)?shù)據(jù)庫的相關(guān)數(shù)據(jù)做了修改,則無法監(jiān)測,此時(shí)必須由應(yīng)用程序負(fù)責(zé)監(jiān)測這一變化,然后手工刷新查詢結(jié)果。Query接口的setForceCacheRefresh(
          true)可以手工刷新查詢結(jié)果。
          在ehcache.xml中添加如下配置:
          <!-- 設(shè)置默認(rèn)的查詢緩存的數(shù)據(jù)過期策略 -->
              
          <cache name="org.hibernate.cache.StandardQueryCache" 
                 maxElementsInMemory
          ="50"
                 eternal
          ="false" 
                 timeToIdleSeconds
          ="3600" 
                 timeToLiveSeconds
          ="7200" 
                 overflowToDisk
          ="true"/>
                  
              
          <!-- 設(shè)置時(shí)間戳緩存的數(shù)據(jù)過期策略 -->
              
          <cache name="org.hibernate.cache.UpdateTimestampsCache" 
                 maxElementsInMemory
          ="5000"
                 eternal
          ="true" 
                 overflowToDisk
          ="true"/>
              
              
          <!-- 設(shè)置自定義命名查詢緩存customerQueries的數(shù)據(jù)過期策略 -->
              
          <cache name="myCacheRegion"
                  maxElementsInMemory
          ="1000"
                  eternal
          ="false"
                  timeToIdleSeconds
          ="300"
                  timeToLiveSeconds
          ="600"
                  overflowToDisk
          ="true"
                  
          /> 

           
          2)      打開查詢緩存:在hibernate.cfg.xml添加如下配置
          <!--啟用查詢緩存 -->
          <property name="cache.use_query_cache">true</property> 

           
          3)      在程序中使用:
          雖然按以上設(shè)置好了查詢緩存,但Hibernate在執(zhí)行查詢語句語句時(shí)仍不會啟用查詢緩存。對于希望啟用查詢緩存的查詢語句,應(yīng)該調(diào)用Query接口的setCacheeable(
          true)方法:
                 測試類如下:
          package org.qiujy.test.cache;
           
          import java.util.List;
           
          import org.hibernate.HibernateException;
          import org.hibernate.Query;
          import org.hibernate.Session;
          import org.hibernate.Transaction;
          import org.qiujy.common.HibernateSessionFactory;
          import org.qiujy.domain.cachedemo.Product;
           
          public class TessQueryCache {
           
                 
          public static void main(String[] args) {
                        Session session 
          = HibernateSessionFactory.getSession();
                        Transaction tx 
          =null;
                        
                        
          try
                               tx 
          = session.beginTransaction(); 
                               Query query 
          = session.createQuery("from Product");
                               
          //激活查詢緩存
                               query.setCacheable(true);
                               
          //使用自定義的查詢緩存區(qū)域,若不設(shè)置,則使用標(biāo)準(zhǔn)查詢緩存區(qū)域
                               query.setCacheRegion("myCacheRegion");
                               
                               List list 
          = query.list();
                               
          for(int i = 0 ; i < list.size(); i++){
                                      Product prod 
          = (Product)list.get(i);
                                      System.out.println(prod.getName());
                               }

                               
                              tx.commit();
                        }
          catch(HibernateException e){
                               
          if(tx != null){
                                      tx.rollback();
                               }

                               e.printStackTrace();
                        }
          finally{
                               HibernateSessionFactory.closeSession();
                        }

                 }

          }
           

           

          轉(zhuǎn)載:http://blog.csdn.net/qjyong/archive/2007/10/07/1814377.aspx

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 界首市| 新竹县| 宜宾市| 微博| 循化| 闸北区| 双流县| 张家川| 镇江市| 长沙县| 石渠县| 化隆| 延川县| 江津市| 拉孜县| 永胜县| 禹州市| 荣昌县| 灌南县| 万荣县| 仁怀市| 兖州市| 西青区| 永寿县| 杭州市| 肇东市| 凤城市| 远安县| 桓仁| 上犹县| 门源| 涡阳县| 开远市| 邯郸县| 嫩江县| 六安市| 睢宁县| 云梦县| 会昌县| 连江县| 林甸县|