我的漫漫程序之旅

          專注于JavaWeb開(kāi)發(fā)
          隨筆 - 39, 文章 - 310, 評(píng)論 - 411, 引用 - 0

          導(dǎo)航

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(39)

          隨筆檔案(43)

          文章分類(304)

          文章檔案(257)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          Hibernate二級(jí)緩存詳解

          與Session相對(duì)的是,SessionFactory也提供了相應(yīng)的緩存機(jī)制。SessionFactory緩存可以依據(jù)功能和目的的不同而劃分為內(nèi)置緩存和外置緩存。

                 SessionFactory的內(nèi)置緩存中存放了映射元數(shù)據(jù)和預(yù)定義SQL語(yǔ)句,映射元數(shù)據(jù)是映射文件中數(shù)據(jù)的副本,而預(yù)定義SQL語(yǔ)句是在 Hibernate初始化階段根據(jù)映射元數(shù)據(jù)推導(dǎo)出來(lái)的。SessionFactory的內(nèi)置緩存是只讀的,應(yīng)用程序不能修改緩存中的映射元數(shù)據(jù)和預(yù)定義 SQL語(yǔ)句,因此SessionFactory不需要進(jìn)行內(nèi)置緩存與映射文件的同步。

                 SessionFactory的外置緩存是一個(gè)可配置的插件。在默認(rèn)情況下,SessionFactory不會(huì)啟用這個(gè)插件。外置緩存的數(shù)據(jù)是數(shù)據(jù)庫(kù)數(shù)據(jù) 的副本,外置緩存的介質(zhì)可以是內(nèi)存或者硬盤。SessionFactory的外置緩存也被稱為Hibernate的二級(jí)緩存。

                 Hibernate的二級(jí)緩存的實(shí)現(xiàn)原理與一級(jí)緩存是一樣的,也是通過(guò)以ID為key的Map來(lái)實(shí)現(xiàn)對(duì)對(duì)象的緩存。

                 由于Hibernate的二級(jí)緩存是作用在SessionFactory范圍內(nèi)的,因而它比一級(jí)緩存的范圍更廣,可以被所有的Session對(duì)象所共享。

          14.2.3.1    二級(jí)緩存的工作內(nèi)容

                 Hibernate的二級(jí)緩存同一級(jí)緩存一樣,也是針對(duì)對(duì)象ID來(lái)進(jìn)行緩存。所以說(shuō),二級(jí)緩存的作用范圍是針對(duì)根據(jù)ID獲得對(duì)象的查詢。

                 二級(jí)緩存的工作可以概括為以下幾個(gè)部分:

          ●   在執(zhí)行各種條件查詢時(shí),如果所獲得的結(jié)果集為實(shí)體對(duì)象的集合,那么就會(huì)把所有的數(shù)據(jù)對(duì)象根據(jù)ID放入到二級(jí)緩存中。

          ●   當(dāng)Hibernate根據(jù)ID訪問(wèn)數(shù)據(jù)對(duì)象的時(shí)候,首先會(huì)從Session一級(jí)緩存中查找,如果查不到并且配置了二級(jí)緩存,那么會(huì)從二級(jí)緩存中查找,如果還查不到,就會(huì)查詢數(shù)據(jù)庫(kù),把結(jié)果按照ID放入到緩存中。

          ●   刪除、更新、增加數(shù)據(jù)的時(shí)候,同時(shí)更新緩存。

          14.2.3.2    二級(jí)緩存的適用范圍

                 Hibernate的二級(jí)緩存作為一個(gè)可插入的組件在使用的時(shí)候也是可以進(jìn)行配置的,但并不是所有的對(duì)象都適合放在二級(jí)緩存中。

                 在通常情況下會(huì)將具有以下特征的數(shù)據(jù)放入到二級(jí)緩存中:

          ●   很少被修改的數(shù)據(jù)。

          ●   不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)。

          ●   不會(huì)被并發(fā)訪問(wèn)的數(shù)據(jù)。

          ●   參考數(shù)據(jù)。

                 而對(duì)于具有以下特征的數(shù)據(jù)則不適合放在二級(jí)緩存中:

          ●   經(jīng)常被修改的數(shù)據(jù)。

          ●   財(cái)務(wù)數(shù)據(jù),絕對(duì)不允許出現(xiàn)并發(fā)。

          ●   與其他應(yīng)用共享的數(shù)據(jù)。

                 在這里特別要注意的是對(duì)放入緩存中的數(shù)據(jù)不能有第三方的應(yīng)用對(duì)數(shù)據(jù)進(jìn)行更改(其中也包括在自己程序中使用其他方式進(jìn)行數(shù)據(jù)的修改,例如,JDBC),因?yàn)槟菢親ibernate將不會(huì)知道數(shù)據(jù)已經(jīng)被修改,也就無(wú)法保證緩存中的數(shù)據(jù)與數(shù)據(jù)庫(kù)中數(shù)據(jù)的一致性。

          14.2.3.3    二級(jí)緩存組件

                 在默認(rèn)情況下,Hibernate會(huì)使用EHCache作為二級(jí)緩存組件。但是,可以通過(guò)設(shè)置 hibernate.cache.provider_class屬性,指定其他的緩存策略,該緩存策略必須實(shí)現(xiàn) org.hibernate.cache.CacheProvider接口。

                 通過(guò)實(shí)現(xiàn)org.hibernate.cache.CacheProvider接口可以提供對(duì)不同二級(jí)緩存組件的支持。

                 Hibernate內(nèi)置支持的二級(jí)緩存組件如表14.1所示。

          表14.1    Hibernate所支持的二級(jí)緩存組件

          組件

          Provider類

          類型

          集群

          查詢緩存

          Hashtable

          org.hibernate.cache.HashtableCacheProvider

          內(nèi)存

          不支持

          支持

          EHCache

          org.hibernate.cache.EhCacheProvider

          內(nèi)存,硬盤

          最新支持

          支持

          OSCache

          org.hibernate.cache.OSCacheProvider

          內(nèi)存,硬盤

          不支持

          支持

          SwarmCache

          org.hibernate.cache.SwarmCacheProvider

          集群

          支持

          不支持

          JBoss TreeCache

          org.hibernate.cache.TreeCacheProvider

          集群

          支持

          支持

                 Hibernate已經(jīng)不再提供對(duì)JCS(Java Caching System)組件的支持了。

          14.2.3.4    二級(jí)緩存的配置

                 在使用Hibernate的二級(jí)緩存時(shí),對(duì)于每個(gè)需要使用二級(jí)緩存的對(duì)象都需要進(jìn)行相應(yīng)的配置工作。也就是說(shuō),只有配置了使用二級(jí)緩存的對(duì)象才會(huì)被放置在二級(jí)緩存中。二級(jí)緩存是通過(guò)<cache>元素來(lái)進(jìn)行配置的。<cache>元素的屬性定義說(shuō)明如下所示:

                

          <cache 

                     
          usage="transactional|read-write|nonstrict-read-write|read-only"               (1)

                     region
          ="RegionName"                                                                                                   (2)

                     include
          ="all|non-lazy"                                                                                                   (3)

          />

                 
          <cache>



          元素的屬性說(shuō)明如表14.2所示。

          表14.2    <cache>元素的屬性說(shuō)明

          序號(hào)

          屬性

          含義和作用

          必須

          默認(rèn)值

          (1)

          usage

          指定緩存策略,可選的策略包括:transactional,read-write,nonstrict-read-write或read-only

          Y

          (2)

          region

          指定二級(jí)緩存區(qū)域名

          N

          (3)

          include

          指定是否緩存延遲加載的對(duì)象。all,表示緩存所有對(duì)象;non-lazy,表示不緩存延遲加載的對(duì)象

          N

          all

          14.2.3.5    二級(jí)緩存的策略

                 當(dāng)多個(gè)并發(fā)的事務(wù)同時(shí)訪問(wèn)持久化層的緩存中的相同數(shù)據(jù)時(shí),會(huì)引起并發(fā)問(wèn)題,必須采用必要的事務(wù)隔離措施。

                 在進(jìn)程范圍或集群范圍的緩存,即第二級(jí)緩存,會(huì)出現(xiàn)并發(fā)問(wèn)題。因此可以設(shè)定以下4種類型的并發(fā)訪問(wèn)策略,每一種策略對(duì)應(yīng)一種事務(wù)隔離級(jí)別。

          ●   只讀緩存(read-only)

                 如果應(yīng)用程序需要讀取一個(gè)持久化類的實(shí)例,但是并不打算修改它們,可以使用read-only緩存。這是最簡(jiǎn)單,也是實(shí)用性最好的策略。

          對(duì)于從來(lái)不會(huì)修改的數(shù)據(jù),如參考數(shù)據(jù),可以使用這種并發(fā)訪問(wèn)策略。

          ●   讀/寫緩存(read-write)

                 如果應(yīng)用程序需要更新數(shù)據(jù),可能read-write緩存比較合適。如果需要序列化事務(wù)隔離級(jí)別,那么就不能使用這種緩存策略。

          對(duì)于經(jīng)常被讀但很少修改的數(shù)據(jù),可以采用這種隔離類型,因?yàn)樗梢苑乐古K讀這類的并發(fā)問(wèn)題。

          ●   不嚴(yán)格的讀/寫緩存(nonstrict-read-write)

                 如果程序偶爾需要更新數(shù)據(jù)(也就是說(shuō),出現(xiàn)兩個(gè)事務(wù)同時(shí)更新同一個(gè)條目的現(xiàn)象很不常見(jiàn)),也不需要十分嚴(yán)格的事務(wù)隔離,可能適用nonstrict-read-write緩存。

          對(duì)于極少被修改,并且允許偶爾臟讀的數(shù)據(jù),可以采用這種并發(fā)訪問(wèn)策略。

          ●   事務(wù)緩存(transactional)

                 transactional緩存策略提供了對(duì)全事務(wù)的緩存,僅僅在受管理環(huán)境中使用。它提供了Repeatable Read事務(wù)隔離級(jí)別。對(duì)于經(jīng)常被讀但很少修改的數(shù)據(jù),可以采用這種隔離類型,因?yàn)樗梢苑乐古K讀和不可重復(fù)讀這類的并發(fā)問(wèn)題。

                 在上面所介紹的隔離級(jí)別中,事務(wù)型并發(fā)訪問(wèn)策略的隔離級(jí)別最高,然后依次是讀/寫型和不嚴(yán)格讀寫型,只讀型的隔離級(jí)別最低。事務(wù)的隔離級(jí)別越高,并發(fā)性能就越低。

          14.2.3.6    在開(kāi)發(fā)中使用二級(jí)緩存

                 在這一部分中,將細(xì)致地介紹如何在Hibernate中使用二級(jí)緩存。在這里所使用的二級(jí)緩存組件為EHCache。

                 關(guān)于EHCache的詳細(xì)信息請(qǐng)參考http://ehcache.sourceforge.net上的內(nèi)容。

                 在Hibernate中使用二級(jí)緩存需要經(jīng)歷以下步驟:

          ●   在Hibernate配置文件(通常為hibernate.cfg.xml)中,設(shè)置二級(jí)緩存的提供者類。

          ●   配置EHCache的基本參數(shù)。

          ●   在需要進(jìn)行緩存的實(shí)體對(duì)象的映射文件中配置緩存的策略。

                 下面就來(lái)逐步演示一下如何在開(kāi)發(fā)中使用Hibernate的二級(jí)緩存。

                 修改Hibernate的配置文件

                 在使用Hibernate的二級(jí)緩存時(shí),需要在Hibernate的配置文件中指定緩存提供者對(duì)象,以便于Hibernate可以通過(guò)其實(shí)現(xiàn)對(duì)數(shù)據(jù)的緩存處理。

                 在這里需要設(shè)置的參數(shù)是hibernate.cache.provider_class,在使用EHCache時(shí),需要將其值設(shè)置為org.hibernate.cache.EhCacheProvider。具體要增加的配置如下所示:

               

            <property name="hibernate.cache.provider_class">           org.hibernate.cache.EhCacheProvider</property>

           

                 Hibernate配置文件的詳細(xì)內(nèi)容請(qǐng)參考配套光盤中的hibernate"src"cn"hxex" hibernate"cache"hibernate.cfg.xml文件。

                 增加EHCache配置參數(shù)

                 在默認(rèn)情況下,EHCache會(huì)到classpath所指定的路徑中尋找ehcache.xml文件來(lái)作為EHCache的配置文件。

                 在配置文件中,包含了EHCache進(jìn)行緩存管理時(shí)的一些基本的參數(shù)。具體的配置方法如清單14.9所示。

                 清單14.9    EHCache的配置

          <?xml version="1.0" encoding="UTF-8"?>

          <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

                 xsi:noNamespaceSchemaLocation
          ="ehcache.xsd">

                 
          <diskStore path="java.io.tmpdir" />

                 
          <defaultCache 

                        
          maxElementsInMemory="10000" 

                        eternal
          ="false" 

                        timeToIdleSeconds
          ="120" 

                        timeToLiveSeconds
          ="120" 

                        overflowToDisk
          ="true" 

                        diskPersistent
          ="false" 

                        diskExpiryThreadIntervalSeconds
          ="120" 

                        memoryStoreEvictionPolicy
          ="LRU" />

          </ehcache>


                 在這里只是使用EHCache所提供的默認(rèn)配置文件進(jìn)行了EHCache的基本配置,對(duì)于這些參數(shù)的詳細(xì)含義請(qǐng)參考其官方網(wǎng)站(http: //ehcache.sourceforge.net/)中的資料。在實(shí)際的開(kāi)發(fā)中,應(yīng)該依據(jù)自己的具體情況來(lái)設(shè)置這些參數(shù)的值。

                 開(kāi)發(fā)實(shí)體對(duì)象

                 這里所使用的是一個(gè)非常簡(jiǎn)單的User對(duì)象,它只包含了ID,name和age三個(gè)屬性,具體的實(shí)現(xiàn)方法請(qǐng)參見(jiàn)配套光盤中的hibernate"src"cn"hxex"cache"User.java文件。

                 配置映射文件

                 映射文件的配置與不使用二級(jí)緩存的Java對(duì)象的區(qū)別就在于需要增加前面所介紹的<cache>元素來(lái)配置此對(duì)象的緩存策略。在這里所使用的緩存策略為“read-write”。所以,應(yīng)該在映射文件中增加如下的配置:

                 <cache usage="read-write"/>

                 映射文件的詳細(xì)配置請(qǐng)參考配套光盤中的hibernate"src"cn"hxex"cache"User.hbm.xml文件。

                 測(cè)試主程序

                 在這里的測(cè)試主程序采用了多線程的運(yùn)行方式,以模擬在不同Session的情況下是否真的可以避免查詢的重復(fù)進(jìn)行。

                 在這個(gè)測(cè)試程序中,所做的工作就是依據(jù)ID來(lái)得到對(duì)應(yīng)的實(shí)體對(duì)象,并將其輸出。然后通過(guò)多次運(yùn)行此程序,來(lái)檢查后面的運(yùn)行是否進(jìn)行了數(shù)據(jù)庫(kù)的操作。

                 測(cè)試主程序的主要測(cè)試方法的實(shí)現(xiàn)如清單14.10所示。

                 清單14.10    測(cè)試主程序的實(shí)現(xiàn)

          ……

           

          public void run() {

                     SessionFactory sf 
          = CacheMain.getSessionFactory();

                     Session session 
          = sf.getCurrentSession();
                     

                     session.beginTransaction();

                     

                     User user 
          = (User)session.get( User.class"1" );

                     System.out.println( user );        

                     session.getTransaction().commit();

          }

                 
          public static void main(String[] args) {

                        CacheMain main1 
          = new CacheMain();
                        main1.start();
                        CacheMain main2 
          = new CacheMain();
                        main2.start();
                 }


          }

              
                 運(yùn)行測(cè)試程序

                 在運(yùn)行測(cè)試程序之前,需要先手動(dòng)地向數(shù)據(jù)庫(kù)中增加一條記錄。該記錄的ID值為1,可以采用下面的SQL語(yǔ)句。

                 INSERT INTO userinfo(userId, name, age) VALUES( '1', 'galaxy', 32 );

                 接下來(lái)在運(yùn)行測(cè)試主程序時(shí),應(yīng)該看到類似下面的輸出:

          Hibernate: select user0_.userId as userId0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from USERINFO user0_ where user0_.userId=?

          ID:  1

          Namge:   galaxy

          Age:       32

          ID:  1

          Namge:   galaxy

          Age:       32

                 通過(guò)上面的結(jié)果可以看到,每個(gè)運(yùn)行的進(jìn)程都輸出了User對(duì)象的信息,但在運(yùn)行中只進(jìn)行了一次數(shù)據(jù)庫(kù)讀取操作,這說(shuō)明第二次User對(duì)象的獲得是從緩存中抓取的,而沒(méi)有進(jìn)行數(shù)據(jù)庫(kù)的查詢操作。

          14.2.3.7    查詢緩存

                 查詢緩存是專門針對(duì)各種查詢操作進(jìn)行緩存。查詢緩存會(huì)在整個(gè)SessionFactory的生命周期中起作用,存儲(chǔ)的方式也是采用key-value的形式來(lái)進(jìn)行存儲(chǔ)的。

                 查詢緩存中的key是根據(jù)查詢的語(yǔ)句、查詢的條件、查詢的參數(shù)和查詢的頁(yè)數(shù)等信息組成的。而數(shù)據(jù)的存儲(chǔ)則會(huì)使用兩種方式,使用SELECT語(yǔ)句只查詢實(shí)體 對(duì)象的某些列或者某些實(shí)體對(duì)象列的組合時(shí),會(huì)直接緩存整個(gè)結(jié)果集。而對(duì)于查詢結(jié)果為某個(gè)實(shí)體對(duì)象集合的情況則只會(huì)緩存實(shí)體對(duì)象的ID值,以達(dá)到緩存空間可 以共用,節(jié)省空間的目的。

                 在使用查詢緩存時(shí),除了需要設(shè)置hibernate.cache.provider_class參數(shù)來(lái)啟動(dòng)二級(jí)緩存外,還需要通過(guò)hibernate.cache.use_query_cache參數(shù)來(lái)啟動(dòng)對(duì)查詢緩存的支持。

                 另外需要注意的是,查詢緩存是在執(zhí)行查詢語(yǔ)句的時(shí)候指定緩存的方式以及是否需要對(duì)查詢的結(jié)果進(jìn)行緩存。

                 下面就來(lái)了解一下查詢緩存的使用方法及作用。

                 修改Hibernate配置文件

                 首先需要修改Hibernate的配置文件,增加hibernate.cache.use_query_cache參數(shù)的配置。配置方法如下:

                 <property name="hibernate.cache.use_query_cache">true</property>

                 Hibernate配置文件的詳細(xì)內(nèi)容請(qǐng)參考配套光盤中的hibernate"src"cn"hxex" hibernate"cache"hibernate.cfg.xml文件。

                 編寫主測(cè)試程序

                 由于這是在前面二級(jí)緩存例子的基礎(chǔ)上來(lái)開(kāi)發(fā)的,所以,對(duì)于EHCache的配置以及視圖對(duì)象的開(kāi)發(fā)和映射文件的配置工作就都不需要再重新進(jìn)行了。下面就來(lái)看一下主測(cè)試程序的實(shí)現(xiàn)方法,如清單14.11所示。

                 清單14.11    主程序的實(shí)現(xiàn)

          ……

             

           public void run() {

                     SessionFactory sf 
          = QueryCacheMain.getSessionFactory();

                     Session session 
          = sf.getCurrentSession();

                     

                     session.beginTransaction();

                     

                     Query query 
          = session.createQuery( "from User" );

                     Iterator it 
          = query.setCacheable( true ).list().iterator();

                     
          while( it.hasNext() ) {

                            System.out.println( it.next() );

                     }


                     

                     User user 
          = (User)session.get( User.class"1" );

                     System.out.println( user );

                     

                     session.getTransaction().commit();

              }


                 
          public static void main(String[] args) {

                        QueryCacheMain main1 
          = new QueryCacheMain();

                        main1.start();

                        

                        
          try {

                               Thread.sleep( 
          2000 );

                        }
           catch (InterruptedException e) {

                               e.printStackTrace();

                        }


                        QueryCacheMain main2 
          = new QueryCacheMain();

                        main2.start();

                 }


          }

                 主程序在實(shí)現(xiàn)的時(shí)候采用了多線程的方式來(lái)運(yùn)行。首先將“from User”查詢結(jié)果進(jìn)行緩存,然后再通過(guò)ID取得對(duì)象來(lái)檢查是否對(duì)對(duì)象進(jìn)行了緩存。另外,多個(gè)線程的執(zhí)行可以看出對(duì)于進(jìn)行了緩存的查詢是不會(huì)執(zhí)行第二次的。

                 運(yùn)行測(cè)試主程序

                 接著就來(lái)運(yùn)行測(cè)試主程序,其輸出結(jié)果應(yīng)該如下所示:

          Hibernate: select user0_.userId as userId0_, user0_.name as name0_, user0_.age as age0_ from USERINFO user0_

          ID:  1

          Namge:   galaxy

          Age:       32

          ID:  1

          Namge:   galaxy

          Age:       32

          ID:  1

          Namge:   galaxy

          Age:       32

          ID:  1

          Namge:   galaxy

          Age:       32

                 通過(guò)上面的執(zhí)行結(jié)果可以看到,在兩個(gè)線程執(zhí)行中,只執(zhí)行了一個(gè)SQL查詢語(yǔ)句。這是因?yàn)楦鶕?jù)ID所要獲取的對(duì)象在前面的查詢中已經(jīng)得到了,并進(jìn)行了緩存,所以沒(méi)有再次執(zhí)行查詢語(yǔ)句。



          posted on 2008-11-04 13:50 々上善若水々 閱讀(40169) 評(píng)論(1)  編輯  收藏 所屬分類: Hibernate

          評(píng)論

          # re: Hibernate二級(jí)緩存詳解  回復(fù)  更多評(píng)論   

          打算
          2015-07-26 15:37 | 現(xiàn)在
          主站蜘蛛池模板: 米脂县| 山丹县| 定安县| 沂源县| 县级市| 嘉义县| 襄樊市| 陵川县| 平塘县| 五寨县| 日照市| 盘锦市| 宜良县| 旅游| 铅山县| 浦北县| 宣汉县| SHOW| 东乡| 乌海市| 水富县| 东乌珠穆沁旗| 柏乡县| 宜兰县| 淳安县| 米易县| 湖南省| 衡南县| 景德镇市| 孝感市| 海兴县| 元阳县| 通化市| 昂仁县| 洛阳市| 宿州市| 临高县| 安图县| 莱芜市| 内乡县| 沙湾县|