Hibernate緩存
緩存是計算機領域的概念,它介於應用程序和永久性數據存儲源(如在硬盤上的文件或者數據庫)之間,其作用是降低應用程序
直接讀寫永久性數據存儲源的頻率,從而提高應用的運行性能。緩存中的數據是數據存儲源中數據的復制,應用程序在運行時直接
讀寫緩存中的數據,只在某些特定時刻按照緩存中的數據來同步更新數據存儲源。
緩存的物理介質通常是內存,而永久性數據存儲源的物理介質通常是硬盤或磁盤,應用程序讀寫內存的速度顯然比讀寫硬盤的速度
快。如果緩存中存放的數據量非常大,也會用硬盤作為緩存的物理介質。
Hibernate緩存一般分為3類:
(1)一級緩存。Session緩存稱為一級緩存。由於Session對象的生命周期通常對應一個數據庫事務,因此它的緩存是事務范圍的緩存。
一級緩存是必需的,Session默認帶有,而且不能卸載。在一級緩存中,持久化類的每個實例都具有唯一的OID。
(2)二級緩存。SessionFactory緩存分為內置緩存和外置緩存。內置緩存是Hibernate自帶的,不可拆卸,是只讀緩存,用來存放映射
元數據和預定義SQL語句。外置緩存是一個可配置的緩存插件,默認SessionFactory不會啟用這個緩存插件。外置緩存中的數據是數據庫
數據的復制。SessionFactory對象的生命周期和應用程序的整個進程對應。二級緩存是可選的,可以在每個類或每個集合的粒度上配置二
級緩存。
(3)查詢緩存。它是Hibernate為查詢結果提供的,依賴於二級緩存。
緩存的作用分為3類
(1)事務范圍。每個事務都有自己的緩存,緩存內數據不會被多個事務並發訪問。例如hibernate的一級緩存,事務是不能跨多個Session的,Session內
數據只能被當前事務訪問,因此它屬於事務范圍的緩存。
(2)進程范圍。進程內的所有事物共享緩存,進程結束,緩存結束生命周期,例如hibernate的二級緩存,SessionFactory對象的生命周期對應應用程序的
整個進程,因此它屬於進程范圍的緩存。
(3)集群范圍。緩存被一個或多個機器上的多個進程共享。Hibernate的二級緩存也可以作為集群范圍的緩存。
一級緩存:
一級緩存的生命周期和session的生命周期一致,當前session一旦關閉,一級緩存就消失了,因此一級緩存也叫session級的緩存或事務級緩存,一級緩存只存實體對象,它不會緩存一般的對象屬性(查詢緩存可以),即當獲得對象后,就將該對象緩存起來,如果在同一session中再去獲取這個對象時,它會先判斷在緩存中有沒有該對象的id,如果有則直接從緩存中獲取此對象,反之才去數據庫中取,取的同時再將此對象作為一級緩存處理。
|
|||
|
|||
以下方法支持一級緩存:
* get()
* load()
* iterate(查詢實體對象)
其中 Query 和Criteria的list() 只會緩存,但不會使用緩存(除非結合查詢緩存)。
二級緩存:
開發中的用途沒有面試帶來作用大。
二級緩存是進程(N個事務)或集群范圍內的緩存,可以被所有的Session共享,在多個事務之間共享
二級緩存是可配置的插件
配置二級緩存的步驟:
*1.引入如下jar包。
ehcache-1.2.3.jar 核心庫
backport-util-concurrent.jar
commons-logging.jar
*2.配置Hibernate.cfg.xml開啟二級緩存
<property name="hibernate.cache.use_second_level_cache">true</property>
*3.配置二級緩存的供應商
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
*4.指定使用二級緩存的類
方案一:在*.hbm.xml中配置
在<class>元素的子元素下添加chche子節點,但該配置僅會緩存對象的簡單屬性,若希望緩存集合屬性中的元素,必須在set元素中添加<cache>子元素
<class name="Student" table="STUDENT">
<cache usage="read-write"/>
方案二:在大配置文件(hibernate.cfg.xml)中配置
位置有限定
Multiple annotations found at this line:
- The content of element type "session-factory" must match "(property*,mapping*,(class-cache|collection-
cache)*,event*,listener*)".
- Start tag of element <session-factory>
<class-cache usage="read-write" class="cn.happy.entity.Student"/>
<collection-cache usage="read-write" collection=""/>
*5.在src下添加ehcache.xml文件,從etc獲取文件即可。
解析 :出現如下錯誤因為沒有添加二級緩存所需jar包
org.hibernate.HibernateException: could not instantiate RegionFactory [org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge]
二級緩存分為:
緩存算法
類級別緩存區
集合級別緩存區
更新時間戳
查詢緩存
query 的list()和iterate()區別 (必記)
解析:
1.返回的類型不一樣,list返回List,iterate返回Iterator,
2.獲取數據的方式不一樣,list會直接查數據庫,iterate會先到數據庫中把id都取出來,然后真正要遍歷某個對象的時候先到緩存中找,如果找不到,以id為條件再發一條sql到數據庫,這樣如果緩存中沒有數據,則查詢數據庫的次數為n+1。
3.iterate會查詢2級緩存,list 只會緩存,但不會使用緩存(除非結合查詢緩存)。
4.list中返回的List中每個對象都是原本的對象,iterate中返回的對象是代理對象
查詢緩存:
1查詢是數據庫技術中最常用的操作,Hibernate為查詢提供了緩存,用來提高查詢速度,優化查詢性能
相同HQL語句檢索結果的緩存!
2查詢緩存依賴於二級緩存
查詢緩存是針對普通屬性結果集的緩存,對實體對象的結果集只緩存id(其id不是對象的真正id,可以看成是HQL或者SQL語句,它與查詢的條件相關即where后的條件相關,不同的查詢條件,其緩存的id也不一樣)。查詢緩存的生命周期,當前關聯的表發生修改或是查詢條件改變時,那么查詢緩存生命周期結束,它不受一級緩存和二級緩存生命周期的影響,要想使用查詢緩存需要手動配置如下:
* 在hibernate.cfg.xml文件中啟用查詢緩存,如:
<property name="hibernate.cache.use_query_cache">true</property>
* 在程序中必須手動啟用查詢緩存,如:
query.setCacheable(true);
其中 Query 和Criteria的list() 就可利用到查詢緩存了。
案例:
//查詢緩存
@Test public void queryTest(){ Session session = HibernateUtils.currentSession(); Transaction tx=session.beginTransaction(); List<Dept> list = session.createQuery("from Dept").setCacheable(true).list(); System.out.println(list.get(0).getDeptName()); tx.commit(); HibernateUtils.closeSession(); Session session2 = HibernateUtils.currentSession(); Transaction tx2=session2.beginTransaction(); List<Dept> list2 = session2.createQuery("from Dept").setCacheable(true).list(); System.out.println(list.get(0).getDeptName()); tx2.commit(); }
總結:
不要想當然的以為緩存可以提高性能,僅僅在你能夠駕馭它並且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的。在不了解原理的情況下亂用,可能會有1+N的問題。不當的使用還可能導致讀出臟數據。 如果受不了hibernate的諸多限制,那么還是自己在應用程序的層面上做緩存吧。
在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數據庫還是要實現自己的緩存,盡管數據庫有緩存,咱們的應用程序還是要做緩存。因為底層的緩存它並不知道高層要用這些數據干什么,只能做的比較通用,而高層可以有針對性的實現緩存,所以在更高的級別上做緩存,效果也要好些吧。
緩存是位於應用程序與物理數據源之間,用於臨時存放復制數據的內存區域,目的是為了減少應用程序對物理數據源訪問的次數,從而提高應用程序的運行性能.
Hibernate在查詢數據時,首先到緩存中去查找,如果找到就直接使用,找不到的時候就會從物理數據源中檢索,所以,把頻繁使用的數據加載到緩存區后,就可以大大減少應用程序對物理數據源的訪問,使得程序的運行性能明顯的提升.