国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Hibernate4之二級緩存
緩存:緩存是什么,解決什么問題?
位于速度相差較大的兩種硬件/軟件之間的,用于協(xié)調(diào)兩者數(shù)據(jù)傳輸速度差異的結(jié)構(gòu),均可稱之為緩存Cache。緩存目的:讓數(shù)據(jù)更接近于應(yīng)用程序,協(xié)調(diào)速度不匹配,使訪問速度更快。

緩存的范圍分為3類:
1.事務(wù)范圍(單Session即一級緩存)
   事務(wù)范圍的緩存只能被當(dāng)前事務(wù)訪問,每個事務(wù)都有各自的緩存,緩存內(nèi)的數(shù)據(jù)通常采用相互關(guān)聯(lián)的對象形式.緩存的生命周期依賴于事務(wù)的生命周期,只有當(dāng)事務(wù)結(jié)束時,緩存的生命周期才會結(jié)束.事務(wù)范圍的緩存使用內(nèi)存作為存儲介質(zhì),一級緩存就屬于事務(wù)范圍.
2.應(yīng)用范圍(單SessionFactory即二級緩存)
   應(yīng)用程序的緩存可以被應(yīng)用范圍內(nèi)的所有事務(wù)共享訪問.緩存的生命周期依賴于應(yīng)用的生命周期,只有當(dāng)應(yīng)用結(jié)束時,緩存的生命周期才會結(jié)束.應(yīng)用范圍的緩存可以使用內(nèi)存或硬盤作為存儲介質(zhì),二級緩存就屬于應(yīng)用范圍.
3.集群范圍(多SessionFactory)
   在集群環(huán)境中,緩存被一個機(jī)器或多個機(jī)器的進(jìn)程共享,緩存中的數(shù)據(jù)被復(fù)制到集群環(huán)境中的每個進(jìn)程節(jié)點,進(jìn)程間通過遠(yuǎn)程通信來保證緩存中的數(shù)據(jù)的一致,緩存中的數(shù)據(jù)通常采用對象的松散數(shù)據(jù)形式.

二級緩存如何工作的
Hibernate的二級緩存同一級緩存一樣,也是針對對象ID來進(jìn)行緩存。所以說,二級緩存的作用范圍是針對根據(jù)ID獲得對象的查詢。
● 在執(zhí)行各種條件查詢時,如果所獲得的結(jié)果集為實體對象的集合,那么就會把所有的數(shù)據(jù)對象根據(jù)ID放入到二級緩存中。
● 當(dāng)Hibernate根據(jù)ID訪問數(shù)據(jù)對象的時候,首先會從Session一級緩存中查找,如果查不到并且配置了二級緩存,那么會從二級緩存中查找,如果還查不到,就會查詢數(shù)據(jù)庫,把結(jié)果按照ID放入到緩存中。
● 刪除、更新、增加數(shù)據(jù)的時候,同時更新緩存。

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

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

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

Hibernate的二級緩存的實現(xiàn)原理與一級緩存是一樣的,也是通過以ID為key的Map來實現(xiàn)對對象的緩存。

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

在通常情況下會將具有以下特征的數(shù)據(jù)放入到二級緩存中:
● 很少被修改的數(shù)據(jù)。
● 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)。
● 不會被并發(fā)訪問的數(shù)據(jù)。
● 常量數(shù)據(jù)。
● 不會被第三方修改的數(shù)據(jù)

而對于具有以下特征的數(shù)據(jù)則不適合放在二級緩存中:
● 經(jīng)常被修改的數(shù)據(jù)。
● 財務(wù)數(shù)據(jù),絕對不允許出現(xiàn)并發(fā)。
● 與其他應(yīng)用共享的數(shù)據(jù)。

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

常見的緩存組件
在默認(rèn)情況下,Hibernate會使用EHCache作為二級緩存組件。但是,可以通過設(shè)置hibernate.cache.provider_class屬性,指定其他的緩存策略,該緩存策略必須實現(xiàn)org.hibernate.cache.CacheProvider接口。
通過實現(xiàn)org.hibernate.cache.CacheProvider接口可以提供對不同二級緩存組件的支持,此接口充當(dāng)緩存插件與Hibernate之間的適配器。
組件Provider類類型集群查詢緩存
Hashtableorg.hibernate.cache.HashtableCacheProvider內(nèi)存不支持支持
EHCacheorg.hibernate.cache.EhCacheProvider內(nèi)存,硬盤不支持支持
OSCacheorg.hibernate.cache.OSCacheProvider內(nèi)存,硬盤支持支持
SwarmCacheorg.hibernate.cache.SwarmCacheProvider集群支持不支持
JBoss TreeCacheorg.hibernate.cache.TreeCacheProvider集群支持支持

Hibernate已經(jīng)不再提供對JCS(Java Caching System)組件的支持了。
集群緩存的概念:
當(dāng)一臺服務(wù)器上的執(zhí)行了update方法修改了一條數(shù)據(jù),那么只有這一臺服務(wù)器上的二級緩存會同步于數(shù)據(jù)庫,其他服務(wù)器上的二級緩存里面這條數(shù)據(jù)就沒意義了。這個時候用OSCache緩存機(jī)制,只要有一臺服務(wù)器上有數(shù)據(jù)修改了,馬上會從配置文件中找到配置好的其他服務(wù)器IP地址,進(jìn)行廣播,告訴他們我這條數(shù)據(jù)修改了,你們也更新同步一下。(是不是有點像手機(jī)上微博的推送功能)

如何在程序里使用二級緩存:
首先在hibernate.cfg.xml開啟二級緩存

Xml代碼  
  1. <hibernate-configuration>  
  2.    <session-factory>  
  3.   
  4.       ......  
  5.   
  6.       <!-- 開啟二級緩存 -->  
  7.       <property name="hibernate.cache.use_second_level_cache">true</property>  
  8.       <!-- 啟動"查詢緩存"如果想緩存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法獲得的數(shù)據(jù)結(jié)果集,必須配置此項-->  
  9.       <property name="hibernate.cache.use_query_cache">true</property>  
  10.       <!-- 設(shè)置二級緩存插件EHCache的Provider類-->  
  11.       <!-- <property name="hibernate.cache.provider_class">  
  12.          org.hibernate.cache.EhCacheProvider  
  13.       </property> -->  
  14.       <!-- 二級緩存區(qū)域名的前綴 -->  
  15.       <!--<property name="hibernate.cache.region_prefix">test</property>-->  
  16.       <!-- 高速緩存提供程序 -->  
  17.       <property name="hibernate.cache.region.factory_class">  
  18.          net.sf.ehcache.hibernate.EhCacheRegionFactory  
  19.       </property>  
  20.       <!-- Hibernate4以后都封裝到org.hibernate.cache.ehcache.EhCacheRegionFactory -->  
  21.       <!-- 指定緩存配置文件位置 -->  
  22.       <!-- <property name="hibernate.cache.provider_configuration_file_resource_path">  
  23.          ehcache.xml  
  24.       </property> -->  
  25.       <!-- 強(qiáng)制Hibernate以更人性化的格式將數(shù)據(jù)存入二級緩存 -->  
  26.       <property name="hibernate.cache.use_structured_entries">true</property>  
  27.   
  28.       <!-- Hibernate將收集有助于性能調(diào)節(jié)的統(tǒng)計數(shù)據(jù) -->  
  29.       <property name="hibernate.generate_statistics">true</property>  
  30.   
  31.       ......  
  32.   
  33.    </session-factory>  
  34. </hibernate-configuration>  

然后是ehcache配置(ehcache.xml)
cache參數(shù)詳解:
● name:指定區(qū)域名
● maxElementsInMemory :緩存在內(nèi)存中的最大數(shù)目
● maxElementsOnDisk:緩存在磁盤上的最大數(shù)目
● eternal :設(shè)置是否永遠(yuǎn)不過期
● overflowToDisk : 硬盤溢出數(shù)目
● timeToIdleSeconds :對象處于空閑狀態(tài)的最多秒數(shù)后銷毀
● timeToLiveSeconds :對象處于緩存狀態(tài)的最多秒數(shù)后銷毀
● memoryStoreEvictionPolicy:緩存算法,有LRU(默認(rèn))、LFU、LFU

關(guān)于緩存算法,常見有三種:
● LRU:(Least Rencently Used)新來的對象替換掉使用時間算最近很少使用的對象
● LFU:(Least Frequently Used)替換掉按命中率高低算比較低的對象
● LFU:(First In First Out)把最早進(jìn)入二級緩存的對象替換掉


Xml代碼  
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ehcache>  
  3.   <!--如果緩存中的對象存儲超過指定的緩存數(shù)量的對象存儲的磁盤地址-->  
  4.   <diskStore path="D:/ehcache"/>  
  5.   
  6.   <!-- 默認(rèn)cache:如果沒有對應(yīng)的特定區(qū)域的緩存,就使用默認(rèn)緩存 -->  
  7.   <defaultCache maxElementsInMemory="10000"  
  8.                 eternal="false"  
  9.                 timeToIdleSeconds="300"   
  10.                 timeToLiveSeconds="600"  
  11.                 overflowToDisk="false"/>  
  12.   <!-- 指定區(qū)域cache:通過name指定,name對應(yīng)到Hibernate中的區(qū)域名即可-->  
  13.   <cache name="cn.javass.h3test.model.UserModel"  
  14.                 eternal="false"  
  15.                 maxElementsInMemory="100"  
  16.                 timeToIdleSeconds="1200"  
  17.                 timeToLiveSeconds="1200"  
  18.                 overflowToDisk="false">  
  19.   </cache>  
  20.   
  21. </ehcache>  

在每個實體的hbm文件中配置cache元素,usage可以是read-only或者是read-write等4種。
Xml代碼  
  1. <?xml version="1.0" encoding='UTF-8'?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC  
  3.                             "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.                             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >  
  5. <hibernate-mapping>      
  6.    <class>  
  7.        <!-- 設(shè)置該持久化類的二級緩存并發(fā)訪問策略 read-only read-write nonstrict-read-write transactional-->  
  8.        <class name="cn.java.test.model.User" table="TBL_USER">  
  9.               <cache usage="read-write"/>  
  10.        ......    
  11.    </class>  
  12. </hibernate-mapping>  

也可以用Hibernate注解配置緩存實體類
Java代碼  
  1. @Entity    
  2. @Table    
  3. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)  
  4. public class User implements Serializable {    
  5.     private static final long serialVersionUID = -5121812640999313420L;  
  6.     private Integer id;  
  7.     private String name;  
  8.   
  9.     ......  
  10. }  

Query或Criteria接口查詢時設(shè)置其setCacheable(true):
默認(rèn)的如果不在程序中顯示的執(zhí)行查詢緩存聲明操作,Hibernate是不會對查詢的list進(jìn)行緩存的。

Java代碼  
  1. Session s1= HibernateSessionFactory.getCurrentSession();  
  2. s1.beginTransaction();  
  3. System.out.println("第一次查詢User");  
  4. Query q = s1.createQuery("from User");  
  5. q.setCacheable(true);  
  6. q.list();  
  7. System.out.println("放進(jìn)二級緩存");  
  8. s1.getTransaction().commit();  
  9.   
  10. Session s2= HibernateSessionFactory.getCurrentSession();  
  11. s2.beginTransaction();  
  12. System.out.println("第二次查詢User,將不會發(fā)出sql");  
  13. Query q = s2.createQuery("from User");  
  14. q.setCacheable(true);  
  15. q.list();  
  16. s2.getTransaction().commit();  
  17.   
  18. //如果配置文件打開了generate_statistics性能調(diào)解,可以得到二級緩存命中次數(shù)等數(shù)據(jù)  
  19. Statistics s = HibernateSessionFactoryUtil.getSessionFactory().getStatistics();  
  20. System.out.println(s);  
  21. System.out.println("put:"+s.getSecondLevelCachePutCount());  
  22. System.out.println("hit:"+s.getSecondLevelCacheHitCount());  
  23. System.out.println("miss:"+s.getSecondLevelCacheMissCount());  

如果開啟了二級緩存,由于session是共享二級緩存的,只要緩存里面有要查詢的對象,就不會向數(shù)據(jù)庫發(fā)出sql,如果在二級緩存里沒有找到需要的數(shù)據(jù)就會發(fā)出sql語句去數(shù)據(jù)庫拿。

一級緩存的管理:
● evit(Object obj)將指定的持久化對象從一級緩存中清除,釋放對象所占用的內(nèi)存資源,指定對象從持久化狀態(tài)變?yōu)槊摴軤顟B(tài),從而成為游離對象.
● clear()將一級緩存中的所有持久化對象清除,釋放其占用的內(nèi)存資源
● contains(Object obj)判斷指定的對象是否存在于一級緩存中.
● flush()刷新一級緩存區(qū)的內(nèi)容,使之與數(shù)據(jù)庫數(shù)據(jù)保持同步.

二級緩存的管理:
● evict(Class arg0, Serializable arg1)將某個類的指定ID的持久化對象從二級緩存中清除,釋放對象所占用的資源.

Java代碼  
  1. sessionFactory.evict(Customer.class, new Integer(1));  

evict(Class arg0)將指定類的所有持久化對象從二級緩存中清除,釋放其占用的內(nèi)存資源
Java代碼  
  1. sessionFactory.evict(Customer.class);  

evictCollection(String arg0)將指定類的所有持久化對象的指定集合從二級緩存中清除,釋放其占用的內(nèi)存資源.
Java代碼  
  1. sessionFactory.evictCollection("Customer.orders");  


設(shè)置一級緩存和二級緩存的交互權(quán)限
Java代碼  
  1. session = HibernateUtils.getSession();  
  2. session.beginTransaction();  
  3.               
  4. //僅向二級緩存讀數(shù)據(jù),而不向二級緩存寫數(shù)據(jù),這里load的數(shù)據(jù)就不會放入二級緩存,下次再查還是會去數(shù)據(jù)庫拿  
  5. session.setCacheMode(CacheMode.GET);  
  6. //只向二級緩存寫數(shù)據(jù),而不從二級緩存讀數(shù)據(jù)  
  7. //session.setCacheMode(CacheMode.PUT);  
  8. //不與二級緩存交互  
  9. //session.setCacheMode(CacheMode.IGNORE);  
  10. //可以與二級緩存交互  
  11. //session.setCacheMode(CacheMode.NORMAL);  
  12.   
  13. Student student = (Student)session.load(Student.class, 1);  
  14.   
  15. session.getTransaction().commit();  

設(shè)置二級緩存策略
READ_ONLY:實體只讀緩存
   只讀緩存不允許更新,將報錯Can't write to a readonly object。
   允許新增,(從2.0以后新增直接添加到二級緩存)

Java代碼  
  1. //確保數(shù)據(jù)庫中有標(biāo)識符為1的FarmModel    
  2. FarmModel farm = (FarmModel) session.get(FarmModel.class, 1);    
  3. //如果修改將報錯,只讀緩存不允許修改    
  4. //farm.setName("aaa");  

NONSTRICT_READ_WRITE:實體非嚴(yán)格讀/寫緩存
   允許更新,更新后緩存失效,需再查詢一次。
   允許新增,新增記錄自動加到二級緩存中。
   整個過程不加鎖。
READ_WRITE:實體讀/寫緩存
   允許更新,更新后自動同步到緩存。
   允許新增,新增記錄后自動同步到緩存。
   保證read committed隔離級別及可重復(fù)讀隔離級別(通過時間戳實現(xiàn))
   整個過程加鎖,如果當(dāng)前事務(wù)的時間戳早于二級緩存中的條目的時間戳,說明該條目已經(jīng)被別的
   事務(wù)修改了,此時重新查詢一次數(shù)據(jù)庫,否則才使用緩存數(shù)據(jù),因此保證可重復(fù)讀隔離級別。
   讀寫緩存和不嚴(yán)格讀寫緩存在實現(xiàn)上的區(qū)別在于,讀寫緩存更新緩存的時候會把緩存里面的數(shù)據(jù)換成一個鎖
TRANSACTIONAL:實體事務(wù)緩存
   緩存支持事務(wù),發(fā)生異常的時候,緩存也能夠回滾,只支持jta環(huán)境
Collection集合緩存

Java代碼  
  1. <hibernate-mapping>  
  2.     <class name="cn.java.test.model.UserModel" table="TBL_USER">  
  3.         <cache usage="read-write" />  
  4.         <set name="farms" cascade="all" inverse="true" lazy="false">  
  5.             <cache usage="read-write"/>  
  6.             <key column="fk_user_id"/>  
  7.             <one-to-many class="cn.java.test.model.FarmModel"/>  
  8.         </set>  
  9.     </class>  
  10. </hibernate-mapping>  


和實體并發(fā)策略有相同含義;
但集合緩存只緩存集合元素的標(biāo)識符,在二級緩存中只存放相應(yīng)實體的標(biāo)識符,然后再通過標(biāo)識符去二級緩存查找相應(yīng)的實體最后組合為集合返回
Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就失效,一個collection緩存僅在這個collection里面的元素有增刪時才失效。
這樣有一個問題,如果你的collection是根據(jù)某個字段排序的,當(dāng)其中一個元素更新了該字段時,導(dǎo)致順序改變時,collection緩存里面的順序沒有做更新

高速緩存區(qū)域
Hibernate在不同的高速緩存區(qū)域保存不同的類(實體)/集合,如果不配置區(qū)域默認(rèn)都保存到“默認(rèn)緩存”(defaultCache)中。
●每一個區(qū)域可以設(shè)置過期策略、緩存條目大小等等。
●對于類緩存,默認(rèn)區(qū)域名是全限定類名,如cn.javass.h3test.model.UserModel。
●對于集合而言,默認(rèn)區(qū)域名是全限定類名+屬性名,如cn.javass.….UserModel.farms。
●可通過hibernate.cache.region_prefix指定特定SessionFactory的區(qū)域前綴,如前綴是h3test,則如類緩存的區(qū)域名就是h3test.cn.javass.h3test.model.UserModel。如果應(yīng)用程序使用多個SessionFactory這可能是必須的。
可通過<cache usage="read-write" region="區(qū)域名"/>自定義區(qū)域名,不過默認(rèn)其實就可以了。

一些對二級緩存的理解
當(dāng)hibernate更新數(shù)據(jù)庫的時候,它怎么知道更新哪些查詢緩存呢?
hibernate在一個地方維護(hù)每個表的最后更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
當(dāng)通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時間和這個緩存所查詢的表,當(dāng)hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。
如果找到的時間戳晚于高速緩存查詢結(jié)果的時間戳,那么緩存結(jié)果將被丟棄,重新執(zhí)行一次查詢。
可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

使用二級緩存的前置條件
對于那些查詢非常多但插入、刪除、更新非常少的應(yīng)用程序來說,查詢緩存可提升性能。但寫入多查詢少的沒有用,總失效。
hibernate程序?qū)?shù)據(jù)庫有獨占的寫訪問權(quán),其他的進(jìn)程更新了數(shù)據(jù)庫,hibernate是不可能知道的。
你操作數(shù)據(jù)庫必需直接通過hibernate,如果你調(diào)用存儲過程,或者自己使用jdbc更新數(shù)據(jù)庫,hibernate也是不知道的。
這個限制相當(dāng)?shù)募郑袝r候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優(yōu)化。
當(dāng)然可以用SessionFactory提供的移除緩存的方法(上面的二級緩存的管理里面有介紹)

總結(jié)
不要想當(dāng)然的以為緩存一定能提高性能,僅僅在你能夠駕馭它并且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當(dāng)?shù)氖褂眠€可能導(dǎo)致讀出臟數(shù)據(jù)。

如果受不了Hibernate的諸多限制,那么還是自己在應(yīng)用程序的層面上做緩存吧!
在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數(shù)據(jù)庫還是要實現(xiàn)自己的緩存,盡管數(shù)據(jù)庫有緩存,咱們的應(yīng)用程序還是要做緩存。因為底層的緩存它并不知道高層要用這些數(shù)據(jù)干什么,只能做的比較通用,而高層可以有針對性的實現(xiàn)緩存,所以在更高的級別上做緩存,效果也要好些吧! 
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
hibernate3-二級緩存配制 EHCache實戰(zhàn)
Hibernate 緩存機(jī)制
Hibernate 數(shù)據(jù)緩存
Hibernate二級緩存【轉(zhuǎn)】新理解
Hibernate緩存
談?wù)凥ibernate緩存使用(一)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服