標籤:一級緩衝 二級緩衝 session 緩衝 緩衝機制
在介紹hibernate的緩衝機制前,我們先瞭解一下什麼是緩衝:
緩衝(Cache): 電腦領域非常通用的概念。裡面放東西,說白了緩衝就是一個集合。它介於應用程式和永久性資料存放區源(如硬碟上的檔案或者資料庫)之間,其作用是降低應用程式直接讀寫永久性資料存放區源的頻率,從而提高應用的運行效能。緩衝中的資料是資料存放區源中資料的拷貝並且緩衝的物理介質通常是記憶體。
瞭解jdbc的人都知道,當需要串連資料庫時,一般都會做一個串連池,那麼串連池和緩衝有什麼區別呢?
相同點:兩者都可以是在記憶體裡,實現時一樣的,都是為了提高效能的。
不同點:串連池是一個重量級的池子,也就是說池子裡面的資源是很寶貴的東西。
下面我們來瞭解一下hibernate中的緩衝機制:一級緩衝、二級緩衝、查詢快取。
一級緩衝:
1、在hibernate中,一個線程對應一個session,一個線程可以看成是一個session,也就是說session是和線程綁定在一起的。
2、理解一級緩衝:
在session介面中包含了一系列的java介面,這些java集合構成了session層級的一級緩衝,只要是session執行個體的生命週期沒有結束,存放在其中的緩衝對象就不會死亡。iterate、load、get、save等都使用使用一級緩衝。
3、一級緩衝的清理
session具有一個緩衝,位於緩衝中的對象稱為持久化對象,他和資料庫中的相關記錄對應,session在某些時間點,按照緩衝中對象的變化來執行相關的sql語句,來同步更新資料庫,這一過程稱為清理緩衝,預設情況下session在以下時間點清理緩衝:
(1)提交事務的時候,會先清理緩衝session.flush();
(2)緩衝中的持久化對象發生變化,會先清理緩衝以保證持久化對象的最新狀態。
(3)顯示調用session.flush();
清理相關的知識點:
session.flush();會清理緩衝,緩衝中德持久化對象不會丟失,會產生insert語句。
session.clear()清空緩衝,緩衝中的持久化對象丟失。
session.reflush()讓session和資料庫同步,執行查詢,把資料庫的最新資訊顯示出來,更新本機快取的對象狀態.。
當session載入了一個對象後,回味該對象的值類型的屬性複製一份快照,當清理緩衝時,通過比較對象的當前屬性和快照,來判斷對象的那些屬性發生了變化,
發生變化的執行sql語句,沒有變化的不執行sql語句。。
在不使用refresh等的情況下,清理緩衝時,要讓一級緩衝中的對象和快照中的對象進行對比,不同的話在提交的時候會產生updata語句。
4、其他知識點
iter = session.createQuery("from Student s where s.id<5").iterate();
while (iter.hasNext()) {
Student student = (Student)iter.next();
System.out.println(student.getName());
iterate在沒有使用緩衝的情況下會有n+1的問題。
第一次iterate查詢會發出N+1條sql語句,第一條sql語句查詢所有的id,然後根據id查詢實體物件,有N個id就發出N條語句查詢實體。
iterate查詢不同的屬性,一級緩衝不會緩衝,因為一級緩衝是用來緩衝實體物件的。
session間不能共有一級緩衝,一級緩衝會伴隨著session的消亡而失效。
二級緩衝:
1、二級緩衝需要sessionFactory來管理,是進程層級的緩衝,所有人都可以使用,是共用的。
2、二級緩衝比較複雜,一般用第三方的產品,hibernate只提供了一個簡單的實現,用hashtable實現的。
3、使用場合:長時間不改變的資料。
4、配置步驟:
(1)ehcache.xml 可以設定預設的,所有的類都遵循這個配置,也可以對某個對象單獨的配置。
(2)在hibernate.cfg.xml設定檔配置緩衝,讓hibernate知道我們使用的是那個二級緩衝。包括配置屬性:是否啟用二級緩衝、二級緩衝的供應商。
(3)手動指定哪些實體類的對象放到緩衝,在hibernate.cfg.xml配置
<class-cache class="com.bjpowernode.hibernate.Student" usage="read-only"/>
或者
在對應檔中的id標籤前面<cache usage="read-only"/>
usage屬性工作表示使用緩衝的策略,一般優先使用read-only,表示如果資料放到緩衝,就不能再修改了,因為經常修改的資料也不需要放到緩衝中。
read-only策略效率好,因為不能改緩衝,但是可能出現髒資料的問題,這個問題的解決方案只能依賴緩衝的逾時,因為可能對象的資料被修改了,但是
緩衝卻沒有變,這樣造成資料不同步,也就是髒資料的問題。
read-write當持久化對象發生變化時,緩衝裡面就會跟著變化,資料庫中也改變了,這種方式需要加上鎖,效率比read-only慢。
5、知識點:
二級緩衝必須讓sessionfactory管理,讓sessionfactory來清除,可以調用evict方法。
查詢資料後會預設放到二級和一級緩衝中,我們也可以控制查詢出來的資料不放到緩衝裡面的,就是說我們可以控制一級緩衝和二級緩衝的交換。
session.setCacheMode(CacheMode.IGNORE);禁止將一級緩衝中的資料往二級緩衝裡放。
和一級緩衝一樣,二級緩衝也不存放普通屬性的查詢資料,這和一級緩衝是一樣的,只存放實體物件。
session層級的緩衝對效能提高沒有太大的意義,因為生命週期太短了。
查詢快取:
1、 一級緩衝和二級緩衝都只是存放實體物件的,如果查詢實體物件的普通屬性的資料,只能放到查詢快取裡面,查詢快取還存放查詢實體物件的id。
2、查詢快取的生命週期不確定,當它關聯的表發生修改時(通過hibernate),查詢快取的生命週期就結束。
3、查詢快取預設是關閉的,可以在hibernate.cfg.xml配置<property name="hibernate.cache.use_query_cache">true</property>。並且必須在程式中手動啟動查詢快取,在query介面中的setCacheable(true)方法來啟用。
4、查詢快取意義不是很大,查詢快取說明白了就是存放由list方法或者iterate方法查詢的資料,我們在查詢時很少出現完全相同的條件查詢,這就是說命中率低,
這樣的緩衝裡的資料總是變化的。除非多次查詢都是查詢相同條件的資料,也就是說返回的結果總是一樣,這樣的緩衝配置才有意義。