天天看點

Hibernate中一級緩存、二級緩存及查詢緩存的總結

一、 一級緩存

1.         一級緩存隻緩存整個對象,不能緩存對象屬性;

2.         一級緩存是Session級的緩存,不能跨多個Session對象來使用;

3.         Session的load/get方法支援一級緩存的讀和寫;

4.         Query的list接口隻支援一級緩存的寫入,不能從一級緩存中讀出對象。list接口加載對象要發出SQL;

5.         Query的iterate接口既支援一級緩存的寫入,也能從一級緩存中讀取對象(如果有的話)。每次用iterate接口查詢對象,都要先發SQL加載查詢對象的id清單。如果需要用到某個對象,則根據該對象的id從一級緩存中查詢,有則直接加載,沒有則發出SQL從資料庫加載(這時會出現1+N問題)。

6.         Session的save方法會将save的對象放入一級緩存中,是以如果要save大批對象,則應該要及時清空一級緩存,可以采用Session的clear()方法。

7.         一級緩存是hibernate 預設使用的,無需配置即可使用。

二、  二級緩存

1.       二級緩存也是隻能緩存整個對象,不能緩存對象屬性,而且對load/get方法、list/iterate方法的在使用上跟一級緩存一樣。

2.       與一級緩存不同,二級緩存是SessionFactory級的緩存,它允許多個Session對象之間共用。

3.       使用二級緩存前必須進行一些準備步驟(以EhCache為例):

(1)    需要有EhCache的xml配置檔案(設定EhCache的“緩存對象最大數目”、“對象是否不失效”、“對象允許的空閑時間”、“對象的生存時間”及“對象數目超額時是否緩存至磁盤”);

(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)    指定需要緩存的類及緩存方式(可在hibernate.cfg.xml或對應的類的.hbm.xml中配置):

在hibernate.cfg.xml中配置:

<class-cache usage="read-only" class="my.Student"/>

在Student.hbm.xml中配置(必須在配置id前完成):

<cache usage="read-only"/>

(5)    可以通過Session動态設定是否允許對二級緩存進行讀和寫,方法是:session.setCacheMode(CacheMode.GET)和session.setCacheMode(CacheMode.PUT)

(6)    SessionFactory的evit()會将一個對象逐處二級緩存。

三、  查詢緩存

查詢緩存是專為Query的list方法設計的。對于iterate()方法,無論是查詢對象屬性還是對象本身,查詢緩存用與不用都沒有差別!

1.用查詢緩存查詢屬性:

(1)    查詢緩存必須要在hibernate.cfg.xml中顯示啟用:

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

(2)    在代碼中如果要用到查詢緩存(無論是寫還是讀緩存),都要進行開啟操作,可通過Query的setCacheable(true)方法開啟;

(3)    查詢緩存的生命周期與Session無關(可以跨Session查詢),當查詢關聯的表發生改變,那麼查詢緩存的生命周期結束(delete、update、modify)

(4)    開啟查詢緩存,并用Query查詢對象的屬性(可以是一個或多個)時,采用Query的list方法可以把得到的屬性集合寫入查詢緩存中。如果查詢緩存已經有了該對象的屬性,那麼就不會發出SQL而直接從查詢緩存中取出來;

2.用查詢緩存查詢對象:

(5)    如果開啟查詢緩存并通過list接口查詢對象,在首次查詢時會發出SQL從資料庫中擷取對象,同時将對象的id清單放入查詢緩存中;如果再次用查詢緩存查詢對象,則會根據該對象的id發出SQL從資料庫中加載對象(這時會發出N條SQL語句)

(6)    如果同時開啟查詢和二級緩存,那麼(5)中就不會發出N條SQL語句了,而是直接從二級緩存中加載。(此時的list接口有了讀二級緩存的能力了!!!)