Hibernate:二级缓存
緩存(Cache):計算機領域非常通用的概念。它介于應用程序和永久性數據存儲源(如硬盤上的文件或者數據庫)之間,其作用是降低應用程序直接讀寫永久性數據存儲源的頻率,從而提高應用的運行性能。緩存中的數據是數據存儲源中數據的拷貝。緩存的物理介質通常是內存。
Hibernate中提供了兩個級別的緩存:
- 第一級別的緩存是 Session 級別的緩存,它是屬于事務范圍的緩存。這一級別的緩存由 hibernate 管理的。
- 第二級別的緩存是 SessionFactory 級別的緩存,它是屬于進程范圍的緩存。
1,一級緩存和二級緩存
Session級別的是一級緩存不需要開發者關心,默認總是有效的,當應用保存持久化實體、修改持久化實體時,Sessioin并不會立即把這種改變flush到數據庫,而是緩存在當前Session的一級緩存中,除非程序顯式調用Session的flush()方法,或程序關閉Session時才會把這些改變一次性的flush到底層數據庫——通過這種緩存,可以減少與數據庫交互,從而提高數據庫訪問性能。
在 Session 接口的實現中包含一系列的 Java 集合,這些 Java 集合構成了 Session 緩存。只要 Session 實例沒有結束生命周期,且沒有清理緩存,則存放在它緩存中的對象也不會結束生命周期。
Session緩存的操作
- flush:Session 按照緩存中對象的屬性變化來同步更新數據庫。
默認情況下 Session 在以下時間點刷新緩存:
- 顯式調用 Session 的 flush() 方法。
- 當應用程序調用 Transaction 的 commit()方法的時, 該方法先 flush ,然后在向數據庫提交事務。
- 當應用程序執行一些查詢(HQL, Criteria)操作時,如果緩存中持久化對象的屬性已經發生了變化,會先 flush 緩存,以保證查詢結果能夠反映持久化對象的最新狀態。
flush 緩存的例外情況:如果對象使用 native 生成器生成 OID,那么當調用 Session 的 save() 方法保存對象時, 會立即執行向數據庫插入該實體的 insert 語句。
commit () 和 flush() 方法的區別:flush 執行一系列 sql 語句,但不提交事務;commit 方法先調用flush() 方法,然后提交事務,意味著提交事務意味著對數據庫操作永久保存下來。
SessionFactory級別的二級緩存時全局性的,應用的所有Session都共享這個二級緩存。不過,SessionFactory級別的二級緩存默認是關閉的,必須由程序顯式開啟。一旦在應用中開啟了二級緩存,當Session需要抓取數據時,Session將會先查找一級緩存,再查找二級緩存,只有當一級緩存和二級緩存中都沒有需要抓取的數據時,才會去查找底層數據庫。在適當情況下,合理地設置Hibernate的二級緩存也可以很好地提高應用的數據庫訪問性能。
SessionFactory 的緩存可以分為兩類:
- 內置緩存: Hibernate 自帶的, 不可卸載。通常在 Hibernate 的初始化階段,Hibernate 會把映射元數據和預定義的 SQL 語句放到 SessionFactory 的緩存中,映射元數據是映射文件中數據(.hbm.xml 文件中的數據)的復制。該內置緩存是只讀的。
- 外置緩存(二級緩存):一個可配置的緩存插件。在默認情況下, SessionFactory 不會啟用這個緩存插件。外置緩存中的數據是數據庫數據的復制,外置緩存的物理介質可以是內存或硬盤。
適合放入二級緩存中的數據:
- 很少被修改。
- 不是很重要的數據, 允許出現偶爾的并發問題。
不適合放入二級緩存中的數據:
- 經常被修改。
- 財務數據, 絕對不允許出現并發問題。
- 與其他應用程序共享的數據。
2,開啟二級緩存
為了開啟Hibernate二級緩存,需要在hibernate.cfg.xml文件中設置如下屬性:
<property name="hibernate.cache.use_second_level_cache">true</property>一旦開啟了二級緩存,并且設置了對某個持久化實體類啟用緩存,SessionFactory就會緩存應用訪問過的該實體類的每個對象,除非緩存的數據超出緩存空間。
實際應用一般不需要開發者自己實現緩存,直接使用第三方提供的開源緩存實現即可。因此,在hibernate.cfg.xml文件中設置開啟緩存后,還需要設置使用哪種二級緩存實現類。
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>二級緩存是可配置的的插件, Hibernate 允許選用以下類型的緩存:
| 緩存 | 緩存實現類 | 類型 | 集群安全 | 查詢緩存支持 |
| ConcurrentHashMap | org.hibernate.testing.cache.CachingRegionFactory | 內存 | ? | ? |
| EhCache | org.hibernate.ache.echache.EhCacheRegionFactory | 內存、緩存、事務性、支持集群 | 是 | 是 |
| Infinispan | org.hibernate.cache.infinispan.InfinispanRegionFactory | 事務性,支持集群 | 是 | 是 |
開啟二級緩存
(1)在hibernate.cfg.xml中開啟二級緩存。需要做兩件事:設置啟用二級緩存&設置二級緩存的實現類。
<property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>(2)將二級緩存的JAR包添加到項目中:將Hibernate目錄下的lib/optional\下的對應緩存的JAR包復制到應用的類加載路徑中,另外還需要另外兩個JAR包。
?(3)將緩存實現所需要的配置文件添加到系統的類加載路徑中。對于EhCache緩存,它需要一個ehcache.xml配置文件
<?xml version="1.0" encoding="GBK" ?> <ehcache><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"/> </ehcache>?(4)設置對哪些實體類、實體的那些集合啟用二級緩存。這一步有兩種方式:
- 修改要使用緩存的持久化類文件,使用Hibernate提供的@Cache注解修飾該持久化類,或使用該注解修飾集合屬性。
- 在hibernate.cfg.xml文件中使用<class-cache.../>或<collection-cache.../>元素對指定的持久化類、集合屬性啟用二級緩存。
上面兩種設置方式只是存在形式不同,本質完全相同。通常來說,推薦采用第一種方式,在這種方式下,不同實體的緩存策略放在不同的持久化類中管理,更符合軟件工程中分而治之的策略。
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) public class Animal {private int id;private String name;public Animal() {}//省略get()和set()方法 }二級緩存的并發訪問策略:兩個并發的事務同時訪問持久層的緩存的相同數據時,也有可能出現各類并發問題。二級緩存可以設定以下 4 種類型的并發訪問策略,每一種訪問策略對應一種事務隔離級別。
- 非嚴格讀寫(Nonstrict-read-write):不保證緩存與數據庫中數據的一致性。提供 Read Uncommited 事務隔離級別,對于極少被修改,而且允許臟讀的數據,可以采用這種策略。
- 讀寫型(Read-write):提供 Read Commited 數據隔離級別。對于經常讀但是很少被修改的數據,可以采用這種隔離類型,因為它可以防止臟讀。
- 事務型(Transactional):僅在受管理環境下適用。它提供了 Repeatable Read 事務隔離級別。對于經常讀但是很少被修改的數據,可以采用這種隔離類型,因為它可以防止臟讀和不可重復讀。
- 只讀型(Read-Only):提供 Serializable 數據隔離級別,對于從來不會被修改的數據,可以采用這種訪問策略。
(5)測測試緩存效果
public class Main {public static void main(String[] args) {Configuration conf = new Configuration().configure();ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();SessionFactory sf = conf.buildSessionFactory(serviceRegistry);Session session = sf.openSession();session.beginTransaction();List<Animal> list = (List<Animal>)session.createQuery("from Animal").list();session.getTransaction().commit();System.out.println("----------------------");// 打開第二個SessionSession sess2 = sf.openSession();sess2.beginTransaction();// 根據主鍵加載實體,系統將直接從二級緩存讀取// 因此不會發出查詢的SQL語句Animal news = (Animal)sess2.load(Animal.class , 1);System.out.println(news.getName());sess2.getTransaction().commit();} }3,管理緩存和統計緩存
1、Session級別的一級緩存是局部緩存,它只對當前Session有效。
對于Session級別的一級緩存而言,所有經過它操作的實體,不管使用save()、update()或saveOrUpdate()方法保存一個對象,還是使用load()、get()、list()、iterate()或scroll()方法獲得一個對象,該對象都將被放入Session級別的一級緩存中——在Session調用flush()方法或close()方法之前,這些對象將一直緩存在一級緩存中。
在某些特殊的情況下,列入正在處理一個大對象(開銷非常大),可能需要從一級緩存中去掉這個大對象或集合屬性,可以調用Session的evict(Object object)方法,將該對象或集合從一級緩存中剔除。如果想把所有的對象都從Session中徹底清除,則調用Session的clear()方法即可。
為了判斷某個對象是否處于Session緩存中,可以借助于Session提供的contains(Object object)方法,該方法返回一個boolean值,用于標識某個實例是否處于當前Session的緩存中。
2、SessionFactory級別的二級緩存是全局緩存,它對所有的Session都有效的。
SessionFactory提供了一個getCache()方法,該方法的返回值是Cache對象,通過該對象即可操作二級緩存中的實體、集合等。
Cache cache = sf.getCache(); //清除指定的News對象 cache.evictEntity(New.class,id); //清除所有的News對象 cache.evictEntiryRegion(News.class); //清除指定id的News所關聯的參與者集合屬性 cache.evictCollection("News.actors,id); //清除所有News所關聯的參與者集合屬性 cache.evictCollection("News.actors");為了更好地統計二級緩存中的內容,可以借助于Hibernate的統計API。為了開啟二級緩存的統計功能,也需要在hibernate.cfg.xml文件中進行配置。
<!--開啟二級緩存的統計功能--> <property name="hibernate.generate_statistics">true</property> <!--設置使用結構化方式來維護緩存項--> <property name="cache.use_structured_entries">true</property>可以通過如下方式查看二級緩存的內容:
// ----------統計二級緩存---------- Map cacheEntries = sf.getStatistics()// 二級緩存的名字默認與持久化類的類名相同.getSecondLevelCacheStatistics("org.crazyit.app.domain.News").getEntries(); System.out.println(cacheEntries);4,查詢緩存
對于經常使用的查詢語句,如果啟用了查詢緩存,當第一次執行查詢語句時,Hibernate 會把查詢結果存放在查詢緩存中。 以后再次執行該查詢語句時,只需從緩存中獲得查詢結果, 從而提高查詢性能,查詢緩存依賴于二級緩存。
查詢緩存使用于如下場合:
- 應用程序運行時經常使用查詢語句。
- 很少對與查詢語句檢索到的數據進行插入, 刪除和更新操作。
啟用查詢緩存的步驟:
- 置二級緩存, 因為查詢緩存依賴于二級緩存。
- 在 hibernate 配置文件中啟用查詢緩存。
- 對于希望啟用查詢緩存的查詢語句, 調用 Query 的 setCacheable() 方法。
?
總結
以上是生活随笔為你收集整理的Hibernate:二级缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机组成原理答案
- 下一篇: 两矩阵相乘的秩的性质_矩阵分析与应用(一