摘要:
Hibernate並沒有為巨型數據集合提供良好的幫助這也許是開發者認為這樣沒有太大必要反而增加Hibernate框架復雜性的緣故吧最近在Hibernate的官方壇子上看到Gavin寫給初級用戶的understand FlushModeNEVER並參考了一下Stripes項目(本人時常關注的時髦項目)作者Tim的blog在閱讀兩位大家言論後和大家share一下
一案件背景
圖片來自於電影《天生殺人狂》
Hibernate並沒有為巨型數據集合提供良好的幫助這也許是開發者認為這樣沒有太大必要反而增加Hibernate框架復雜性的緣故吧於是極大數據量==批量處理Hibernate/java不是批處理的最佳場所的觀念在Hibernate開發中大行其道有些開發者甚至直接利用Hibernate建立session獲取其connection進而進行jdbc操作Jdbc並不是古董但在Hibernate中再次call它難免有些令人無奈最近在Hibernate的官方壇子上看到Gavin寫給初級用戶的understand FlushModeNEVER並參考了一下Stripes項目(本人時常關注的時髦項目)作者Tim的blog在閱讀兩位大家言論後和大家share一下
二性能殺手何在?
圖片來自於電影《這個殺手不太冷》
Tim在其Blog寫道我目前的DNA重組系統具有復雜而海量的OLTP數據對付這些在內存的復雜對象(數千個)的方式是依賴用戶接口(非批量處理)來實現用例驅動這句半開玩笑的話是我想起了那男耕女織的生產力低下的生活真的讓每個開發者都使用算盤運算嗎?
sessionsetFlushMode(FlushModeNEVER);
這條語句及其簡單但解決了大問題它告知Hibernate session無論何時也不要flush任何的狀態變化到數據庫除非開發者直接調用sessionflush()聽上去很合乎邏輯但它為何在一些場景中對性能影響甚深而在其他的場景中卻好似輕如鵝毛般?
在Tim的項目中存在著一個十分典型的case(我也不大了解生物這不能怪我)在實驗中利用PCR Primers對遺傳基因(genes)和DNA中的核苷酸序列(exons)這裡的PCR Primers是在PCR處理過程中用於檢測DNA片段的物質對不起大家本人對生物學詞匯實在無能為力檢測匹配過程大致分為以下步
.發現本次實驗中所有exons(個數在個以上)
.查詢本次實驗所有已經排序的PCR Primers
.查詢本次實驗所有待排序的PCR Primers
.得到與exons對應的Primers找出那些無需轉換的部分
.在系統中為無需轉換的區域查詢所有可能的PCR Primers
.測試每個primer找出最佳exons匹配者(Primer)
.保存找出的Primer
不用擔心步驟細節不大明白也不會影響後面的理解
由於domain model極其海量在第步我們可能在一個session中排序個對象而在步的查詢將帶來個附加對象有趣之處在於當執行第步將對象save到數據庫時沒有一個前面裝載的對象被修改過整個實驗的目的就是僅僅獲得這個對象
在回顧了Tim的生物學場景之後讓我們重新回到FlushModeNEVER的討論上來吧你可能認為既然直到最後一步都沒有修改或是持久化任何東西那麼改變flush模式將收效甚微當然這是不正確的未參透實質的理解實際上在上面流程的起始設置Never這個flush模式在流程終點手動flush將節省一半的run time請注意這裡僅提到了run time而沒有將內存IO計算在內
三這個殺手不太冷
圖片來自於電影《黑衣人》
幸好這個殺手不太冷!這都歸結於Hibernate的髒檢查(dirty checking)每次裝載一個對象到內存(不能去evict它)時session始終跟蹤它的修改於是每次對數據的查詢session都將跌代所有的session中的對象並檢查髒數據將髒數據flush到數據庫Hibernate這樣做的良苦用心是為了確保在執行查詢之前所有可能影響查詢的變化都被提交到數據庫這對零星數據量的應用來講不足為言但面對數千個對象和千余次的查詢來講它將使性能的真正殺手
了解真相後我們可以使用sessionsetFlushMode(FlushModeNEVER)語句將在查詢時不需髒檢查的數據(生物實驗中的Primers)標識髒數據這樣Hibernate無處不在的代理機制將被欺騙直接將它添加到髒數據列表(列表中的數據不會被flush到數據庫)中這樣殺手就會因無處遁形而自動消失了
四打造制勝武器
圖片來自於電影《致命武器》
在讀完這個簡短的案件後我們也學到了如何在一個session中讀取查詢大量數據對象情況下的制勝武器 FlushModeNEVER當然要記住在此過程中你不可以修改這些數據不然就真的把數據搞髒了
使用武器秘訣如下
FlushMode previous = sessiongetFlushMode();
sessionflush(); // who knows what been done till now
sessionsetFlushMode(FlushModeNEVER);
// Do some querying
// Do some more querying
// Really load up that session
// Execute a few more queries
// Write back to some tables
sessionflush();
sessionsetFlushMode(previous);
五聯系作者
cleverpig:
Tim的Blog:
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28397.html