Hibernate之一級快取和二級快取
1:Hibernate的一級快取:
1.1:使用一級快取的目的是為了減少對資料庫的訪問次數,從而提升hibernate的執行效率;(當執行一次查詢操作的時候,執行第二次查詢操作,先檢查快取中是否有資料,如果有資料就不查詢資料庫,直接從快取中獲取資料);
1.2:Hibernate中的一級快取,也叫做session的快取,它可以在session範圍內減少資料庫的訪問次數,只在session範圍內有效,session關閉,一級快取失敗;
1.3:一級快取的特點,只在session範圍有效,作用時間短,效果不是特別明顯,在短時間內多次操作資料庫,效果比較明顯。
1.4:當呼叫session的save/saveOrUpdate/get/load/list/iterator方法的時候,都會把物件放入session快取中;
1.5:session的快取是由hibernate維護的,使用者不能操作快取內容;如果想操作快取內容,必須通過hibernate提供的evict/clear方法操作
1.6:快取相關的方法(在什麼情況下使用上面方法呢?批量操作情況下使用,如Session.flush();先與資料庫同步,Session.clear();再清空一級快取內容):
session.flush();讓一級快取與資料庫同步;
session.evict();清空一級快取中指定的物件;
session.clear();清空一級快取中所有的物件;
1.7:面試題,不同的session是否會共享快取資料?
答:不會哦~~~
1.8:list和iterator的區別?
(1)list查詢:
答: 一次性把所有的記錄都查詢出來了;會放入快取,不會從快取中取資料;
(2)iterate(N+1次查詢):
答: N表示所有的記錄總數,即會發送一條語句查詢所有的記錄的主鍵,這是第一條查詢語句,再根據每一個主鍵取資料庫查詢,這是根據第一次查詢的條數進行N次查詢操作;會放入快取,也會從快取中取出資料;
2:Hibernate的懶載入:
2.1:懶載入概念:當用到資料的時候才向資料庫查詢,這就是hibernate的懶載入特性。
使用懶載入的目的,是提高程式執行效率。
2.2:查詢操作:get()方法/load()方法
(1)get()方法,及時載入。及時查詢操作;只要呼叫get方法立刻向資料庫查詢。
(2)load()方法,預設懶載入,即在使用資料的時候,才向資料庫傳送查詢的sql語句。session關閉以後,不可以使用懶載入。
#懶載入預設為true,即為懶載入,可以改為非懶載入。即lazy="false" #lazy="false" 關閉懶載入 #lazy="true"使用懶載入 #lazy="extra"在真正使用資料的時候才向資料庫傳送查詢的sql語句。集合屬性懶載入的時候提升效率。如果呼叫集合的size()/isEmpty()方法只是統計,不真正查詢資料。 <class name="類名稱" table="資料表名稱" lazy="false"> ...... </class>
2.3:懶載入異常:
Session關閉後,不能使用懶載入資料,如果session關閉後,使用懶載入資料報錯如:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) at com.bie.lesson05.Dept_$$_javassist_1.getDeptName(Dept_$$_javassist_1.java) at com.bie.lesson05.ManyToManyTest.lazyTest(ManyToManyTest.java:241) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
如何解決session關閉後不能使用懶載入載入資料的問題:
方式一:可以先在關閉session之前使用一下資料,這樣關閉以後就可以使用此資料了。如Dept.getDeptName();
方式二(推薦):強迫代理物件初始化操作:Hibernate.initialize(物件);
方式三:關閉懶載入(lazy="false");
方式四(推薦):在使用資料之後再關閉session;
3:二級快取:
Hibernate提供的快取
有一級快取、二級快取。 目的是為了減少對資料庫的訪問次數,提升程式執行效率!
一級快取:
基於Session的快取,快取內容只在當前session有效,session關閉,快取內容失效!
特點:
作用範圍較小! 快取的事件短。
快取效果不明顯。
3.1:二級快取概述:
二級快取:
Hibernate提供了基於應用程式級別的快取即為二級快取,可以跨多個session,即不同的session都可以訪問快取資料。 這個快取也叫二級快取。
Hibernate提供的二級快取有預設的實現,且是一種可插配的快取框架!如果使用者想用二級快取,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影響程式碼。
如果使用者覺得hibernate提供的框架框架不好用,自己可以換其他的快取框架或自己實現快取框架都可以。
3.2:檢視hibernate.properties配置檔案,二級快取如何配置?
########################## ### Second-level Cache ### ########################## #hibernate.cache.use_second_level_cache false【二級快取預設不開啟,需要手動開啟】 #hibernate.cache.use_query_cache true 【開啟查詢快取】 ## choose a cache implementation 【二級快取框架的實現】 #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 預設實現 #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider
3.3:二級快取,使用步驟:
1) 開啟二級快取;
2)指定快取框架;
3)指定那些類加入二級快取;
4)測試;
<!--****************** 【二級快取配置】****************** --> <!-- a. 開啟二級快取 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- b. 指定使用哪一個快取框架(預設提供的) --> <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property> <!-- 開啟查詢快取 --> <property name="hibernate.cache.use_query_cache">true</property> <!-- c. 指定哪一些類,需要加入二級快取 --> <class-cache usage="read-write" class="com.bie.lesson11.Dept"/> <class-cache usage="read-only" class="com.bie.lesson11.Employee"/> <!-- 集合快取[集合快取的元素物件,也加加入二級快取] --> <collection-cache usage="read-write" collection="com.bie.lesson11.Dept.emps"/>
3.4:快取策略:
<class-cache usage="read-only"/> 放入二級快取的物件,只讀; <class-cache usage="nonstrict-read-write"/> 非嚴格的讀寫 <class-cache usage="read-write"/> 讀寫; 放入二級快取的物件可以讀、寫; <class-cache usage="transactional"/> (基於事務的策略)