Hibernate二級快取
Hibernate中沒有自己去實現二級快取,而是利用第三方的。簡單敘述一下配置過程,也作為自己以後用到的時候配置的一個參考。
1、我們需要加入額外的二級快取包,例如EHcache,將其包匯入。需要:ehcache-core-2.4.3.jar , hibernate-ehcache-4.2.4.Final.jar ,slf4j-api-1.6.1.jar
2、在hibernate.cfg.xml配置檔案中配置我們二級快取的一些屬性(此處針對的是Hibernate4):
<!-- 啟用二級快取 --> <property name="cache.use_second_level_cache">true</property> <!-- 配置使用的二級快取的產品 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
3、我們使用的是EHcache,所以我們需要建立一個ehcache.xml的配置檔案,來配置我們的快取資訊,這個是EHcache要求的。該檔案放到根目錄下。
<ehcache> <!-- 指定一個目錄:當 EHCache 把資料寫到硬碟上時, 將把資料寫到這個目錄下. --> <diskStore path="d:\\tempDirectory"/> <!--Default Cache configuration. These will applied to caches programmatically created through the CacheManager. The following attributes are required for defaultCache: maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used if the element is not eternal. Idle time is now - last accessed time timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used if the element is not eternal. TTL is now - creation time overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <!-- 設定快取的預設資料過期策略 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!-- 設定具體的命名快取的資料過期策略。每個命名快取代表一個快取區域 快取區域(region):一個具有名稱的快取塊,可以給每一個快取塊設定不同的快取策略。 如果沒有設定任何的快取區域,則所有被快取的物件,都將使用預設的快取策略。即:<defaultCache.../> Hibernate 在不同的快取區域儲存不同的類/集合。 對於類而言,區域的名稱是類名。如:com.atguigu.domain.Customer 對於集合而言,區域的名稱是類名加屬性名。如com.atguigu.domain.Customer.orders --> <!-- name: 設定快取的名字,它的取值為類的全限定名或類的集合的名字 maxElementsInMemory: 設定基於記憶體的快取中可存放的物件最大數目 eternal: 設定物件是否為永久的, true表示永不過期, 此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 預設值是false timeToIdleSeconds:設定物件空閒最長時間,以秒為單位, 超過這個時間,物件過期。 當物件過期時,EHCache會把它從快取中清除。如果此值為0,表示物件可以無限期地處於空閒狀態。 timeToLiveSeconds:設定物件生存最長時間,超過這個時間,物件過期。 如果此值為0,表示物件可以無限期地存在於快取中. 該屬性值必須大於或等於 timeToIdleSeconds 屬性值 overflowToDisk:設定基於記憶體的快取中的物件數目達到上限後,是否把溢位的物件寫到基於硬碟的快取中 --> <cache name="com.atguigu.hibernate.entities.Employee" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> <cache name="com.atguigu.hibernate.entities.Department.emps" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" /> </ehcache>
4、開啟二級快取。我們在這裡使用的xml的配置方式,所以要在Customer.hbm.xml檔案加一點配置資訊:
<cache usage="read-only"/>
注意是在標籤內。 如果是使用註解的方法,在要在Customer這個類中,加入@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
這個註解。
5、下面我們再進行一下測試。還是上面的程式碼:
@Test public void test() { Customer customer1 = (Customer) session.load(Customer.class, 1); System.out.println(customer1.getCustomerName()); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); Customer customer2 = (Customer) session.load(Customer.class, 1); System.out.println(customer2.getCustomerName()); }
我們可以發現控制檯只發出了一條SQL語句。這是我們二級快取的一個小Demo。
我們的二級快取是sessionFactory級別的,所以當我們session關閉再開啟之後,我們再去查詢物件的時候,此時Hibernate會先去二級快取中查詢是否有該物件。
同樣,二級快取快取的是物件,如果我們查詢的是物件的一些屬性,則不會加入到快取
我們通過二級快取是可以解決之前提到的N+1問題。
已經寫了這麼多了,但好像我們關於快取的內容還沒有講完。不要著急,再堅持一下,我們的內容不多了。我們還是通過一個例子來引出下一個話題。 我們說通過二級快取可以快取物件,那麼我們看一下下面的程式碼以及輸出結果:
@Test
public void test() {
List<Customer> customers1 = session.createQuery("from Customer").list();
System.out.println(customers1.size());
tansaction.commit();
session.close();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
List<Customer> customers2 = session.createQuery("from Customer").list();
System.out.println(customers2.size());
}
會發現控制檯有兩條SQL語句輸出,我們的快取好像沒有起作用哎?這是為啥?當我們通過list()去查詢兩次物件的時候,二級快取雖然會快取插敘出來的物件,但不會快取我們的hql查詢語句,要想解決這個問題,我們需要用到查詢快取。
查詢快取
在前文中也提到了,我們的一級二級快取都是對整個實體進行快取,它不會快取普通屬性,如果想對普通屬性進行快取,則可以考慮使用查詢快取。
但需要注意的是,大部分情況下,查詢快取並不能提高應用程式的效能,甚至反而會降低應用效能,因此實際專案中要謹慎的使用查詢快取。
對於查詢快取來說,它快取的key就是查詢所用的HQL或者SQL語句,需要指出的是:查詢快取不僅要求所使用的HQL、SQL語句相同,甚至要求所傳入的引數也相同,Hibernate才能直接從快取中取得資料。只有經常使用相同的查詢語句、並且使用相同查詢引數才能通過查詢快取獲得好處,查詢快取的生命週期直到屬性被修改了為止。
查詢快取預設是關閉。要想使用查詢快取,只需要在hibernate.cfg.xml中加入一條配置即可:
<property name="hibernate.cache.use_query_cache">true</property>
而且,我們在查詢hql語句時,要想使用查詢快取,就需要在語句中設定這樣一個方法:setCacheable(true)
。
但需要注意的是,我們在開啟查詢快取的時候,也應該開啟二級快取。因為如果不使用二級快取,也有可能出現N+1的問題。
這是因為查詢快取快取的僅僅是物件的ID,所以首先會通過一條SQL將物件的ID都查詢出來,但是當我們後面要得到每個物件的資訊的時候,此時又會發送SQL語句,所以如果我們使用查詢快取,一定也要開啟二級快取。