Hibernate效能優化的常用措施
Hibernate是筆者使用了超過5年的優秀ORM框架,雖然說使用了5年,但筆者並沒有把握說自己真正意義上的精通Hibernate。說道熟悉Hibernate還差不多,因為Hibernate用法和特性只要使用過或許都很簡單,但是要做到發揮Hibernate最大限度的潛力,Hibernate優化,或者說Hibernate效能優化筆者僅僅是初窺門徑而已。這裡摘錄一篇牛人對於Hibernate優化的文章,希望對自己以後的使用指引下方向吧。這篇是上一篇的續作,著實是不錯,推薦hibernate使用者,尤其是像我一樣的使用者看看,會有收穫的
1. HQL調優
1.1 索引調優
HQL看起來和SQL很相似。從HQL的WHERE子句中通常可以猜到相應的SQL WHERE子句。WHERE子句中的欄位決定了資料庫將選擇的索引。
大多數Hibernate開發者所常犯的一個錯誤是無論何時,當需要新WHERE子句的時候都會建立一個新的索引。因為索引會帶來額外的資料更新開銷,所以應該爭取建立少量索引來覆蓋儘可能多的查詢。
讓你使用一個集合來處理所有可能的資料搜尋條件。如果這不太實際,那麼你可以使用後端剖析工具來建立一個針對應用程式涉及的所有 SQL的集合。基於那些搜尋條件的分類,你最終會得到一個小的索引集。與此同時,還可以嘗試向WHERE子句中新增額外的謂語來匹配其他WHERE子句。
範例
有兩個UI搜尋器和一個後端守護程序搜尋器來搜尋名為iso_deals的表。第一個UI搜尋器在unexpectedFlag、dealStatus、tradeDate和isold屬性上有謂語。
第二個UI搜尋器基於使用者鍵入的過濾器,其中包括的內容除tradeDate和isold以外還有其他屬性。開始時所有這些過濾器屬性都是可選的。
後端搜尋器基於isold、participantCode和transactionType屬性。
經過進一步業務分析,發現第二個UI搜尋器實際是基於一些隱式的unexpectedFlag和dealStatus值來選擇資料的。我們還讓tradeDate成為過濾器的必要屬性(為了使用資料庫索引,每個搜尋過濾器都應該有必要屬性)。鑑於這一點,我們依次使用unexpectedFlag、dealStatus、tradeDate和isold構造了一個複合索引。兩個UI搜尋 器都能共用它。(順序很重要,如果你的謂語以不同的順序指定這些屬性或在它們前羅列了其他屬性,資料庫就不會選擇該複合索引。)
後端搜尋器和UI搜尋器區別太大,因此我們不得不為它構造另一個複合索引,依次使用isold、participantCode和transactionType。
1.2繫結引數 vs.字串拼接
既可以使用繫結引數構造HQL的WHERE子句,也可以使用字串拼接的方法,該決定對效能會有一定影響。使用繫結引數的原因是讓資料庫一次解析 SQL,對後續的重複請求複用生成好的執行計劃,這樣做節省了CPU時間和記憶體。然而,為達到最優的資料訪問效率,不同的繫結值可能需要不同的SQL執行 計劃。
例如,一小段資料範圍可能只返回資料總量的5%,而一大段資料範圍可能返回資料總量的90%。前者使用索引更好,而後者則最好使用全表掃描。
建議OLTP使用繫結引數,資料倉庫使用字串拼接,因為OLTP通常在一個事務中重複插入和更新資料,只取少量資料;資料倉庫通常只有少量SQL查詢,有一個確定的執行計劃比節省CPU時間和記憶體更為重要。
要是你知道你的OLTP搜尋對不同繫結值應該使用相同執行計劃又該怎麼辦呢?
Oracle 9i及以後版本在第一次呼叫繫結引數並生成執行計劃時能探出引數值。後續呼叫不會再探測,而是重用之前的執行計劃。
1.3聚合及排序
你可以在資料庫中進行聚合和“order by”,也可以在應用程式的服務層中事先載入所有資料然後做聚合和“order by”操作。推薦使用前者,因為資料庫在這方面通常會比你的應用程式做得好。此外,這樣做還能節省網路頻寬,這也是一種擁有跨資料庫移植性的做法。
當你的應用程式對資料聚合和排序有HQL不支援的特定業務規則時除外。
1.4本地查詢
本地查詢調優其實並不直接與HQL有關。但HQL的確可以讓你直接向底層資料庫傳遞本地查詢。我們並不建議這麼做,因為本地查詢在資料庫間不可移植。
2.抓取策略調優
抓取策略決定了在應用程式需要訪問關聯物件時,Hibernate以何種方式以及何時獲取關聯物件。我們在此將關注它的使用方法。
2.1覆蓋抓取策略
不同的使用者可能會有不同的資料抓取要求。Hibernate允許在兩個地方定義資料抓取策略,一處是在對映元資料中,另一處是在HQL或Criteria中覆蓋它。
常見的做法是基於主要的抓取用例在對映元資料中定義預設抓取策略,針對少數用例在HQL和Criteria中覆蓋抓取策略。
假設pojoA和pojoB是父子關係例項。如果根據業務規則,只是偶爾需要從實體兩端載入資料,那你可以宣告一個延遲載入集合或代理抓取 (proxy fetching)。當你需要從實體兩端獲取資料時,可以用立即抓取(eager fetching)覆蓋預設策略,例如使用HQL或Criteria配置連線抓取(join fetching)。
另一方面,如果業務規則在大多數時候需要從實體兩端載入資料,那麼你可以宣告立即抓取並在Criteria中設定延遲載入集合或代理抓取來覆蓋它(HQL目前還不支援這樣的覆蓋)。
2.2 N+1模式或是反模式?
select抓取會導致N+1問題。如果你知道自己總是需要從關聯中載入資料,那麼就該始終使用連線抓取。在下面兩個場景中,你可能會把N+1視為一種模式而非反模式。
第一種場景,你不知道使用者是否會訪問關聯物件。如果他/她沒有訪問,那麼你贏了;否則你仍然需要額外的N次select SQL語句。這是一種令人左右為難的局面。
第二種場景,pojoA和很多其他POJO有one-to-many關聯,例如pojoB和pojoC。使用立即的內連線或外連線抓取會在結果集中 將pojoA重複很多次。當pojoA中有很多非空屬性時,你不得不將大量資料載入到持久層中。這種載入需要很多時間,既有網路頻寬的原因,如果 Hibernate的會話是有狀態的,其中也會有會話快取的原因(記憶體消耗和GC暫停)。
如果你有一個很長的one-to-many關聯鏈,例如從pojoA到pojoB到pojoC以此類推,情況也是類似的。
你也許會去使用HQL中的DISTINCT關鍵字或Cirteria中的distinct功能或是Java的Set介面來消除重複資料。但所有這些都是在Hibernate(在持久層)中實現的,而非資料庫中。
如果基於你的網路和記憶體配置的測試表明N+1效能更好,那麼你可以使用批量抓取、subselect抓取或二級快取來做進一步調優。
範例
以下是一個使用批量抓取的HBM檔案片段:
<class name="pojoA" table="pojoA"> … <set name="pojoBs" fetch="select" batch-size="10"> <key column="pojoa_id"/> … </set> </class>
以下是多端pojoB生成的SQL:
select … from pojoB where pojoa_id in(?,?,?,?,?, ?,?,?,?,?);
問號數量與batch-size值相等。因此N次額外的關於pojoB的select SQL語句被減少到了N/10次。
如果將fetch=“select“替換成fetch=“subselect“,pojoB生成的SQL語句就是這樣的:
select … from pojoB where pojoa_id in(select id from pojoA where …);
儘管N次額外的select減少到1次,但這隻在重複執行pojoA的查詢開銷很低時才有好處。
如果pojoA中的pojoB集合很穩定,或pojoB有pojoA的many-to-one關聯,而且pojoA是隻讀引用資料,那麼你可以使用二級快取來快取pojoA以消除N+1問題。
2.3延遲屬性抓取
除非有一張擁有很多你不需要的欄位的遺留表,否則不應該使用這種抓取策略,因為它的延遲屬性分組會帶來額外的SQL。
在業務分析和設計過程中,你應該將不同資料獲取或修改分組放到不同的領域物件實體中,而不是使用這種抓取策略。
如果不能重新設計遺留表,可以使用HQL或Criteria提供的投影功能來獲取資料。
3. 二級快取調優
3.3版及以後版本不再推薦使用基於“CacheProvider”的快取,而用基於“RegionFactory”的快取,這也讓人更糊塗了。但是就算是最新的3.5參考文件也沒有提及如何使用新快取方法。
出於下述考慮,我們將繼續關注於老方法:
- 所有流行的Hibernate二級快取提供商中只有JBoss Cache 2、Infinispan 4和Ehcache 2支援新方法。OSCache、SwarmCache、Coherence和Gigaspaces XAP-Data Grid只支援老方法。
- 兩種方法共用相同的<cache>配置。例如,它們仍舊使用相同的usage屬性值“transactional|read-write|nonstrict-read-write|read-only”。
- 多個cache-region介面卡仍然內建老方法的支援,理解它能幫助你快速理解新方法。
3.1 基於CacheProvider的快取機制
理解該機制是做出合理選擇的關鍵。關鍵的類/介面是CacheConcurrencyStrategy和它針對4中不同快取使用的實現類,還有EntityUpdate/Delete/InsertAction。
針對併發快取訪問,有三種實現模式:
- 針對“read-only”的只讀模式。
無論是鎖還是事務都沒影響,因為快取自資料從資料庫載入後就不會改變。
- 針對“read-write”和“nonstrict-read-write”的非事務感知(non-transaction-aware)讀寫模式。
對快取的更新發生在資料庫事務完成後。快取需要支援鎖。
- 針對“transactional”的事務感知讀寫。
對快取和資料庫的更新被包裝在同一個JTA事務中,這樣快取與資料庫總是保持同步的。資料庫和快取都必須支援JTA。儘管快取事務內部依賴於快取鎖,但Hibernate不會顯式呼叫任何的快取鎖函式。
以資料庫更新為例。EntityUpdateAction對於事務感知讀寫、“read-write”的非事務感知讀寫,還有“nonstrict-read-write”的非事務感知讀寫相應有如下呼叫序列:
- 在一個JTA事務中更新資料庫;在同一個事務中更新快取。
- 軟鎖快取;在一個事務中更新資料庫;在上一個事務成功完成後更新快取;否則釋放軟鎖。
軟鎖只是一種特定的快取值失效表述方式,在它獲得新資料庫值前阻止其他事務讀寫快取。那些事務會轉而直接讀取資料庫。
快取必須支援鎖;事務支援則不是必須的。如果快取是一個叢集,“更新快取”的呼叫會將新值推送給所有副本,這通常被稱為“推(push)”更新策略。
- 在一個事務中更新資料庫;在上一個事務完成前就清除快取;為了安全起見,無論事務成功與否,在事務完成後再次清除快取。
既不需要支援快取鎖,也不需要支援事務。如果是快取叢集,“清除快取”呼叫會讓所有副本都失效,這通常被稱為“拉(pull)”更新策略。
對於實體的刪除或插入動作,或者集合變更,呼叫序列都是相似的。
實際上,最後兩個非同步呼叫序列仍能保證資料庫和快取的一致性(基本就是“read committed”的隔離了級別),這要歸功於第二個序列中的軟鎖和“更新資料庫”後的“更新快取”,還有最後一個呼叫序列中的悲觀“清除快取”。
基於上述分析,我們的建議是:
- 如果資料是隻讀的,例如引用資料,那麼總是使用“read-only”策略,因為它是最簡單、最高效的策略,也是叢集安全的策略。
- 除非你真的想將快取更新和資料庫更新放在一個JTA事務裡,否則不要使用“transactional”策略,因為JTA需要漫長的兩階段提交處理,這導致它基本是效能最差的策略。
依筆者看來,二級快取並非一級資料來源,因此使用JTA也未必合理。實際上最後兩個呼叫序列在大多數場景下是個不錯的替代方案,這要歸功於它們的資料一致性保障。
- 如果你的資料讀很多或者很少有併發快取訪問和更新,那麼可以使用“nonstrict-read-write”策略。感謝它的輕量級“拉”更新策略,它通常是效能第二好的策略。
- 如果你的資料是又讀又寫的,那麼使用“read-write”策略。這通常是效能倒數第二的策略,因為它要求有快取鎖,快取叢集中使用重量級的“推”更新策略。
範例
以下是一個ISO收費型別的HBM檔案片段:
<class name="IsoChargeType"> <property name="isoId" column="ISO_ID" not-null="true"/> <many-to-one name="estimateMethod" fetch="join" lazy="false"/> <many-to-one name="allocationMethod" fetch="join" lazy="false"/> <many-to-one name="chargeTypeCategory" fetch="join" lazy="false"/> </class>
一些使用者只需要ISO收費型別本身;一些使用者既需要ISO收費型別,還需要它的三個關聯物件。簡單起見,開發者會立即載入所有三個關聯物件。如果專案中沒人負責Hibernate調優,這是很常見的。
因為所有的關聯物件都是隻讀引用資料,另一種方法是使用延遲抓取,開啟這些物件的二級快取以避免N+1問題。實際上前一種方法也能從引用資料快取中獲益。
因為大多數專案都有很多被其他資料引用的只讀引用資料,上述兩種方法都能改善全域性系統性能。
3.2 RegionFactory
下表是新老兩種方法中對應的主要類/介面:
新方法 | 老方法 |
RegionFactory | CacheProvider |
Region | Cache |
EntityRegionAccessStrategy | CacheConcurrencyStrategy |
CollectionRegionAccessStrategy | CacheConcurrencyStrategy |
第一個改進是RegionFactory構建了特定的Region,例如EntityRegion和TransactionRegion,而不是使 用一個通用的訪問Region。第二個改進是對於特定快取的“usage”屬性值,Region要求構建自己的訪問策略,而不是所有Region都一直使 用CacheConcurrencyStrategy的4種實現。
要使用新方法,應該設定factory_class而非provider_class配置屬性。以Ehcache 2.0為例:
<property name="hibernate.cache.region.factory_class">
net.sf.ehcache.hibernate.EhCacheRegionFactory
</property>
其他相關的Hibernate快取配置都和老方法一樣。
新方法也能向後相容遺留方法。如果還是隻配了CacheProvider,新方法中將使用下列自說明(self-explanatory)介面卡和橋隱式地呼叫老的介面/類:
RegionFactoryCacheProviderBridge、EntityRegionAdapter、 CollectionRegionAdapter、QueryResultsRegionAdapter、 EntityAccessStrategyAdapter和CollectionAccessStrategyAdapter
3.3 查詢快取
二級快取也能快取查詢結果。如果查詢開銷很大而且要重複執行,這也會很有幫助。
4. 批量處理調優
大多數Hibernate的功能都很適合那些每個事務都通常只處理少量資料的OLTP系統。但是,如果你有一個數據倉庫或者事務需要處理大量資料,那麼就另當別論了。
4.1使用有狀態會話的非DML風格批處理
如果你已經在使用常規會話了,那這是最自然的方法。你需要做三件事:
- 配置下列3個屬性以開啟批處理特性:
hibernate.jdbc.batch_size 30 hibernate.jdbc.batch_versioned_data true hibernate.cache.use_second_level_cache false
batch_size設定為正值會開啟JDBC2的批量更新,Hibernate的建議值是5到30。基於我們的測試,極低值和極高值效能都很差。只要取值在合理範圍內,區別就只有幾秒而已。如果網路夠快,這個結果是一定的。
第二個配置設為true,這要求JDBC驅動在executeBatch()方法中返回正確的行數。對於Oracle使用者而言,批量更新時不能將其設為true。請閱讀Oracle的《JDBC Developer’s Guide and Reference》中的“標準批處理的Oracle實現中的更新計數”(Update Counts in the Oracle Implementation of Standard Batching)以獲得更多詳細資訊。因為它對批量插入來說還是安全的,所以你可以為批量插入建立單獨的專用資料來源。最後一個配置項是可選的,因為你可以在會話中顯式關閉二級快取。
- 像如下範例中那樣定期重新整理(flush)並清除一級會話快取:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); //if your hibernate.cache.use_second_level_cache is true, call the following: session.setCacheMode(CacheMode.IGNORE); session.save(customer); if (i % 50 == 0) { //50, same as the JDBC batch size //flush a batch of inserts and release memory: session.flush(); session.clear(); } } tx.commit(); session.close();
批處理通常不需要資料快取,否則你會將記憶體耗盡並大量增加GC開銷。如果記憶體有限,那這種情況會很明顯。
- 總是將批量插入巢狀在事務中。
每次事務修改的物件數量越少就意味著會有更多資料庫提交,每次提交都會帶來磁碟相關的開銷。
另一方面,每次事務修改的物件數量越多就意味著鎖定變更時間越長,同時資料庫需要更大的redo log。
4.2使用無狀態會話的非DML風格批處理
無狀態會話執行起來比上一種方法更好,因為它只是JDBC的簡單包裝,而且可以繞開很多常規會話要求的操作。例如,它不需要會話快取,也不和任何二級快取或查詢快取有互動。
然而它的用法並不簡單。尤其是它的操作並不會級聯到所關聯的例項上;你必須自己來處理它們。
4.3 DML風格
使用DML風格的插入、更新或刪除,你直接在資料庫中操作資料,這和前兩種方法在Hibernate中操作資料的情況有所不同。
因為一個DML風格的更新或刪除相當於前兩種方法中的多個單獨的更新或刪除,所以如果更新或刪除中的WHERE子句暗示了恰當的資料庫索引,那麼使用DML風格的操作能節省網路開銷,執行得更好。
強烈建議結合使用DML風格操作和無狀態會話。如果使用有狀態會話,不要忘記在執行DML前清除快取,否則Hibernate將會更新或清除相關快取。
4.4批量載入
如果你的HQL或Criteria會返回很多資料,那麼要注意兩件事:
- 用下列配置開啟批量抓取特性:
hibernate.jdbc.fetch_size 10
fetch_size設定為正值將開啟JDBC批量抓取特性。相對快速網路,在慢速網路中這一點更為重要。Oracle建議的經驗值是10。你應該基於自己的環境進行測試。
- 在使用上述任一方法時都要關閉快取,因為批量載入一般是一次性任務。受限於記憶體容量,向快取中載入大量資料通常也意味著它們很快會被清除出去,這會增加GC開銷。
範例
我們有一個後臺任務,分段載入大量的IsoDeal資料用於後續處理。我們還會在分段資料交給下游系統處理前將其更新為處理中狀態。最大的一段有50萬行資料。以下是原始程式碼中截取出來的一段:
Query query = session.createQuery("FROM IsoDeal d WHERE chunk-clause"); query.setLockMode("d", LockMode.UPGRADE); //for Inprocess status update List<IsoDeal> isoDeals = query.list(); for (IsoDeal isoDeal : isoDeals) { //update status to Inprocess isoDeal.setStatus("Inprocess"); } return isoDeals;
包含上述程式碼的方法加上了Spring 2.5宣告式事務的註解。載入並更新50萬行資料大約花了10分鐘。我們識別出了以下這些問題:
- 由於會話快取和二級快取的原因,系統會頻繁地記憶體溢位。
- 就算沒有記憶體溢位,當記憶體消耗很高時GC的開銷也會很大。
- 我們還未設定fetch_size。
- 就算我們設定了batch_size,for迴圈也建立了太多update SQL語句。
不幸的是Spring 2.5不支援Hibernate無狀態會話,所以我們只能關閉二級快取;設定fetch_size;用DML風格的更新來代替for迴圈,以此改善效能。
但是,執行時間還是要6分鐘。將Hibernate的日誌級別調成trace後,我們發現是更新會話快取造成了延時。通過在DML更新前清除會話快取,我們將時間縮短到了4分鐘,全部都是將資料載入到會話快取中花費的時間。
5. SQL生成調優
本節將向你展示如何減少SQL生成的數量。
5.1 N+1抓取問題
“select抓取”策略會導致N+1問題。如果“連線抓取”策略適合你的話,你應該始終使用該策略避免N+1問題。
但是,如果“連線抓取”策略執行效果不理想,你可以使用“subselect抓取”、“批量抓取”或“延遲集合抓取”來減少所需的額外SQL語句數。
5.2 Insert+Update問題
範例
我們的ElectricityDeal與DealCharge有單向one-to-many關聯,如下列HBM檔案片段所示:
<class name="ElectricityDeal" select-before-update="true" dynamic-update="true" dynamic-insert="true"> <id name="key" column="ID"> <generator class="sequence"> <param name="sequence">SEQ_ELECTRICITY_DEALS</param> </generator> </id> … <set name="dealCharges" cascade="all-delete-orphan"> <key column="DEAL_KEY" not-null="false" update="true" on-delete="noaction"/> <one-to-many class="DealCharge"/> </set> </class>
在“key”元素中,“not-null”和“update”對應的預設值是false和true,上述程式碼為了明確這些取值,將它們寫了出來。
如果你想建立一個ElectricityDeal和十個DealCharge,會生成如下SQL語句:
- 1句ElectricityDeal的插入語句;
- 10句DealCharge的插入語句,其中不包括外來鍵“DEAL_KEY”;
- 10句DealCharge欄位“DEAL_KEY”的更新語句。
為了消除那額外的10句更新語句,可以在那10句DealCharge插入語句中包含“DEAL_KEY”,你需要將“not-null”和“update”分別修改為true和false。
另一種做法是使用雙向或many-to-one關聯,讓DealCharge來管理關聯。
5.3 更新前執行select
在範例11中,我們為ElectricityDeal加上了select-before-update,這會對瞬時(transient)物件或分離(detached)物件產生額外的select語句,但卻能避免不必要的資料庫更新。
你應該做出一些權衡,如果物件沒多少屬性,不需要防止不必要的資料庫更新,那麼就不要使用該特性,因為你那些有限的資料既沒有太多網路傳輸開銷,也不會帶來太多資料庫更新開銷。
如果物件的屬性較多,例如是一張大的遺留表,那你應該開啟該特性,和“dynamic-update”結合使用以避免太多資料庫更新開銷。
5.4 級聯刪除
在範例11中,如果你想刪除1個ElectricityDeal和它的100個DealCharge,Hibernate會對DealCharge做100次刪除。
如果將“on-delete”修改為“cascade”,Hibernate不會執行DealCharge的刪除動作;而是讓資料庫根據ON CASCADE DELETE約束自動刪除那100個DealCharge。不過,需要讓DBA開啟ON CASCADE DELETE約束,大多數DBA不願意這麼做,因為他們想避免父物件的意外刪除級聯到它的依賴物件上。此外,還要注意,該特性會繞過Hibernate對 版本資料(versioned data)的常用樂觀鎖策略。
5.5 增強的序列識別符號生成器
範例11中使用Oracle的序列作為識別符號生成器。假設我們儲存100個ElectricityDeal,Hibernate會將下面的SQL語句執行100次來獲取下一個可用的識別符號:
select SEQ_ELECTRICITY_DEALS.NEXTVAL from dual;
如果網路不是很快,那這無疑會降低效率。3.2.3及後續版本中增加了一個增強的生成器“SequenceStyleGenerator”,它帶了兩個優化器:hilo和pooled。兩個優化器都使用了HiLo演算法,該演算法生成的識別符號等於Hi值加上Lo值,其中Hi值代表組號,Lo值順序且重複地從1迭代到最大組大小,組號在Lo值“轉回到”1時加1。
假設組大小是5(可以用max_lo或increment_size引數來表示),下面是個例子:
- hilo優化器
組號取自資料庫序列的下一個可用值,Hi值由Hibernate定義,是組號乘以increment_size引數值。
- pooled優化器
Hi值直接取自資料庫序列的下一個可用值。資料庫序列的增量應該設定為increment_size引數值。
直到記憶體組中的值耗盡後,兩個優化器才會去訪問資料庫,上面的例子每5個標識值符訪問一次資料庫。使用hilo優化器時,你的序列不能再被其他應用程式使用,除非它們使用與Hibernate相同的邏輯。使用pooled優化器,在其他應用程式使用同一序列時則相當安全。
兩個優化器都有一個問題,如果Hibernate崩潰,當前組內的一些識別符號值就會丟失,然而大多數應用程式都不要求擁有連續的識別符號值(如果你的資料庫,比方說Oracle,快取了序列值,當它崩潰時你也會丟失識別符號值)。
如果在範例11中使用pooled優化器,新的id配置如下:
<id name="key" column="ID"> <generator class="org.hibernate.id.enhance.SequenceStyleGenerator"> <param name="sequence_name">SEQ_ELECTRICITY_DEALS</param> <param name="initial_value">0</param> <param name="increment_size">100</param> <param name="optimizer ">pooled</param> </generator> </id>
6 總結
本文涵蓋了大多數你在Hibernate應用程式調優時會覺得很有用的調優技巧,其中的大多數時間都在討論那些行之有效卻缺乏文件的調優主題,例如繼承對映、二級快取和增強的序列識別符號生成器。
它還提到了一些Hibernate調優所必需的資料庫知識。一些範例中包含了你可能遇到的問題的實際解決方案。
除此之外,值得一提的是Hibernate也可以和In-Memory Data Grid(IMDG)一起使用,例如Oracle的Coherance或GigaSpaces IMDG,這能讓你的應用程式達到毫秒級別。
關於作者
Yongjun Jiao是SunGard Consulting Services的技術主管。過去10年中他一直是專業軟體開發者,他的專長包括Java SE、Java EE、Oracle和應用程式調優。他最近的關注點是高效能運算,包括記憶體資料網格、平行計算和網格計算。
Stewart Clark是SunGard Consulting Services的負責人。過去15年中他一直是專業軟體開發者和專案經理,他的專長包括Java核心程式設計、Oracle和能源交易。
英文地址:http://www.infoq.com/articles/hibernate_tuning
歡迎有識之士加入我們的技術交流群:361579846