二級緩存(sessionFactory):
Hibernate的二級緩存由SessionFactory對象管理,是應用級別的緩存。它可以緩存整個應用的持久化對象,所以又稱為“SessionFactory緩存”.
hibernate二級緩存中的緩存對象可以被整個應用的Session對象共享,即使關閉當前Session對象,新建的Session對象仍可使用。使用Hibernate的二級緩存之后查詢數據,Session對象會首先在以及緩存中查找有無緩存數據被命中。如果沒有,則查找二級緩存。如果有,則直接返回所命中的數據;否則查詢數據庫
下面介紹在hibernate中如何開啟和使用二級緩存:
1.在hibernate.cfg.xml中開啟二級緩存,並且配置cache.region.factory_class:
<!-- 開啟二級緩存 -->
<property name="cache.use_second_level_cache">false</property>
<!-- 配置cache.region.factory_classs -->
<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
2:導入第三方jar包,(下載hibernate資源包,會在\lib\optional\ehcache文件夾下找到相關jar包):

3.在src目錄下,新建ehcache.xml.或在hibernate資源包的\project\etc目錄下找到該文件,copy到src目錄下:
ehcache.xml:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<!-- maxElementsInMemory:設置存放對象數量的最大值 eternal:設置是否永久存儲 timeToIdleSeconds:設置對象的空閑時間 timeToLiveSeconds:設置對象的存活時間 overflowToDisk:內存溢出是否寫入磁盤 -->
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
/>
<cache name="sampleCache1" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"
/>
<cache name="sampleCache2" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false"
/></ehcache>
4:在需要使用二級緩存的實體類的hbm.xml文件中設置,或在hibernate.cfg.xml中指定需要使用二級緩存的實體類:
以上一節的Book和Category為例,如果我需要開啟Book的二級緩存:
*在Book.hbm.xml文件中的class標簽下,添加一個標簽:
<cache usage="read-only"/>
*或在hibernate.cfg.xml的mapping屬性下面,添加:
<class-cache usage="read-only" class="com.wang.pojo.Book"/>
關於usage的取值,有以下幾種:
只讀緩存(read-only):如果應用程序需要讀取一個持久化類的實例,但是並不打算修改它們,可以使用read-only緩存。這是最簡單,也是實用性最好的策略.
讀/寫緩存(read-write): 如果應用程序需要更新數據,可能read-write緩存比較合適。如果需要序列化事務隔離級別,那么就不能使用這種緩存策略。
不嚴格的讀/寫緩存(nonstrict-read-write):如果程序偶爾需要更新數據(也就是說,出現兩個事務同時更新同一個條目的現象很不常見),也不需要十分嚴格的事務隔離,可能適用nonstrict-read-write緩存。
事務緩存(transactional): transactional緩存策略提供了對全事務的緩存,僅僅在受管理環境中使用。它提供了Repeatable Read事務隔離級別。對於經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止臟讀和不可重復讀這類的並發問題。
以上配置工作全部完成,我們來用代碼,感受一下二級緩存的存在:
Session session=HibernateUtil.getSession(); Book book =(Book) session.get(Book.class,1); System.out.println(book.getName()); session.beginTransaction().commit(); session.close(); System.out.println(book.getName());
在這段代碼中,我先查詢了一下id=1的Book信息,然后關閉了session對象,很明顯一級緩存肯定是不存在了,然后我再次打印book的name,我們先看看控制台的打印信息:

神奇的是發生了,居然沒有報錯,而且打印出了book的name,這就是二級緩存的作用.現在我們再來看看開頭的第二段內容,就一目了然了.
hibernate二級緩存中的緩存對象可以被整個應用的Session對象共享,即使關閉當前Session對象,新建的Session對象仍可使用。使用Hibernate的二級緩存之后查詢數據,Session對象會首先在以及緩存中查找有無緩存數據被命中。如果沒有,則查找二級緩存。如果有,則直接返回所命中的數據;否則查詢數據庫
查詢緩存:
查詢緩存緩存的是查詢出來的實體的部分屬性結果集和實體的ID(注意這里不是實體).關於查詢緩存和二級緩存的同時和分開使用的情況,網絡上這一段解釋的比較好,這里直接引用了:
當只是用Hibernate查詢緩存而關閉二級緩存的時候:
第一:如果查詢的是部分屬性結果集: 那么當第二次查詢的時候就不會發出SQL,直接從Hibernate查詢緩存中取數據;
第二:如果查詢的是實體結果集eg(from Student) ,首先Hibernate查詢緩存存放實體的ID,第二次查詢的時候就到Hibernate查詢緩存中取出ID 一條一條的到數據庫查詢,這樣,將發出N 條SQL造成了SQL泛濫。當都開啟Hibernate查詢緩存和二級緩存的時候:
第一:如果查詢的是部分屬性結果集: 這個和上面只是用Hibernate查詢緩存而關閉 二級緩存的時候一致,因為不涉及實體不會用到二級緩存;
第二:如果查詢的是實體結果集eg(from Student),首先Hibernate查詢緩存存放實體的ID,第二次查詢的時候,就到Hibernate查詢緩存中取出ID,到二級緩存區找數據,如果有數據,就不會發出SQL;如果都有,一條SQL都不會發出,直接從二級緩存中取數據。
下面介紹如何開啟和使用查詢緩存:
1.在hibernate.cfg.xml中.添加一個標簽語句:
<!-- 開啟查詢緩存 -->
<property name="cache.use_query_cache">true</property>
2.在代碼中添加query.setCachemodel(true);
List<Book> list =(List) session.createQuery("from Book") .setCacheable(true)//使用查詢緩存
.list(); System.out.println(list.get(0).getName()); session.beginTransaction().commit(); session.close(); System.out.println(list.get(0).getName());
這里使用了list(),查詢所有Book信息,關閉session以后再次打印list中的內容,依然能打印出來,不會報錯,這就是查詢緩存的使用.
注意:
查詢緩存的生命周期與Session無關(可以跨Session查詢),當查詢關聯的表發生改變,那么查詢緩存的生命周期結束(delete、update、modify)
查詢緩存是專為Query的list方法設計的。對於iterate()方法,無論是查詢對象屬性還是對象本身,查詢緩存用與不用都沒有區別!
