Hibernate的優化方案

1、批量修改和刪除
  在Hibernate 2中,若是須要對任何數據進行修改和刪除操做,都須要先執行查詢操做,在獲得要修改或者刪除的數據後,再對該數據進行相應的操做處理。在數據量少的狀況下采用這種處理方式沒有問題,但須要處理大量數據的時候就可能存在如下的問題:
   佔用大量的內存。
   須要屢次執行update/delete語句,而每次執行只能處理一條數據。
  以上兩個問題的出現會嚴重影響系統的性能。所以,在Hibernate 3中引入了用於批量更新或者刪除數據的HQL語句。這樣,開發人員就能夠一次更新或者刪除多條記錄,而不用每次都一個一個地修改或者刪除記錄了。
  若是要刪除全部的User對象(也就是User對象所對應表中的記錄),則能夠直接使用下面的HQL語句:
  delete User
  而在執行這個HQL語句時,須要調用Query對象的executeUpdate()方法,具體的實例以下所示:
  String HQL="delete User";
  Query query=session.createQuery(HQL);
  int size=query.executeUpdate();
  採用這種方式進行數據的修改和刪除時與直接使用JDBC的方式在性能上相差無幾,是推薦使用的正確方法。
  若是不能採用HQL語句進行大量數據的修改,也就是說只能使用取出再修改的方式時,也會遇到批量插入時的內存溢出問題,因此也要採用上面所提供的處理方法來進行相似的處理。
  2、 使用SQL執行批量操做
  在進行批量插入、修改和刪除操做時,直接使用JDBC來執行原生態的SQL語句無疑會得到最佳的性能,這是由於在處理的過程當中省略或者簡化了如下處理內容:
  ● HQL語句到SQL語句的轉換。
  ● Java對象的初始化。
  ● Java對象的緩存處理。
  可是在直接使用JDBC執行SQL語句時,有一個最重要的問題就是要處理緩存中的Java對象。由於經過這種底層方式對數據的修改將不能通知緩存去進行相應的更新操做,以保證緩存中的對象與數據庫中的數據是一致的。
  3、 提高數據庫查詢的性能
  數據庫查詢性能的提高也是涉及到開發中的各個階段,在開發中選用正確的查詢方法無疑是最基礎也最簡單的。
  1 、SQL語句的優化
  使用正確的SQL語句能夠在很大程度上提升系統的查詢性能。得到一樣數據而採用不一樣方式的SQL語句在性能上的差距多是十分巨大的。
  因爲Hibernate是對JDBC的封裝,SQL語句的產生都是動態由Hibernate自動完成的。Hibernate產生SQL語句的方式有兩種:一種是經過開發人員編寫的HQL語句來生成,另外一種是依據開發人員對關聯對象的訪問來自動生成相應的SQL語句。
  至於使用什麼樣的SQL語句能夠得到更好的性能要依據數據庫的結構以及所要獲取數據的具體狀況來進行處理。在肯定了所要執行的SQL語句後,能夠經過如下三個方面來影響Hibernate所生成的SQL語句:
   HQL語句的書寫方法。
   查詢時所使用的查詢方法。
   對象關聯時所使用的抓取策略。
  2 、使用正確的查詢方法
  在前面已經介紹過,執行數據查詢功能的基本方法有兩種:一種是獲得單個持久化對象的get()方法和load()方法,另外一種是Query對象的list()方法和iterator()方法。在開發中應該依據不一樣的狀況選用正確的方法。
  get()方法和load()方法的區別在於對二級緩存的使用上。load()方法會使用二級緩存,而get()方法在一級緩存沒有找到的狀況下會直接查詢數據庫,不會去二級緩存中查找。在使用中,對使用了二級緩存的對象進行查詢時最好使用load()方法,以充分利用二級緩存來提升檢索的效率。
  list()方法和iterator()方法之間的區別能夠從如下幾個方面來進行比較。
   執行的查詢不一樣
  list()方法在執行時,是直接運行查詢結果所須要的查詢語句,而iterator()方法則是先執行獲得對象ID的查詢,而後再根據每一個ID值去取得所要查詢的對象。所以,對於list()方式的查詢一般只會執行一個SQL語句,而對於iterator()方法的查詢則可能須要執行N+1條SQL語句(N爲結果集中的記錄數)。
  iterator()方法只是可能執行N+1條數據,具體執行SQL語句的數量取決於緩存的狀況以及對結果集的訪問狀況。
   緩存的使用
  list()方法只能使用二級緩存中的查詢緩存,而沒法使用二級緩存對單個對象的緩存(可是會把查詢出的對象放入二級緩存中)。因此,除非重複執行相同的查詢操做,不然沒法利用緩存的機制來提升查詢的效率。
  iterator()方法則能夠充分利用二級緩存,在根據ID檢索對象的時候會首先到緩存中查找,只有在找不到的狀況下才會執行相應的查詢語句。因此,緩存中對象的存在與否會影響到SQL語句的執行數量。
   對於結果集的處理方法不一樣
  list()方法會一次得到全部的結果集對象,並且它會依據查詢的結果初始化全部的結果集對象。這在結果集很是大的時候必然會佔據很是多的內存,甚至會形成內存溢出狀況的發生。
  iterator()方法在執行時不會一次初始化全部的對象,而是根據對結果集的訪問狀況來初始化對象。所以在訪問中能夠控制緩存中對象的數量,以免佔用過多緩存,致使內存溢出狀況的發生。使用iterator()方法的另一個好處是,若是隻須要結果集中的部分記錄,那麼沒有被用到的結果對象根本不會被初始化。因此,對結果集的訪問狀況也是調用iterator()方法時執行數據庫SQL語句多少的一個因素。
  因此,在使用Query對象執行數據查詢時應該從以上幾個方面去考慮使用何種方法來執行數據庫的查詢操做。
  4、 使用正確的抓取策略
  所謂抓取策略(fetching strategy)是指當應用程序須要利用關聯關係進行對象獲取的時候,Hibernate獲取關聯對象的策略。抓取策略能夠在O/R映射的元數據中聲明,也能夠在特定的HQL或條件查詢中聲明。
  Hibernate 3定義瞭如下幾種抓取策略。
   鏈接抓取(Join fetching)
  鏈接抓取是指Hibernate在得到關聯對象時會在SELECT語句中使用外鏈接的方式來得到關聯對象。
   查詢抓取(Select fetching)
  查詢抓取是指Hibernate經過另一條SELECT語句來抓取當前對象的關聯對象的方式。這也是經過外鍵的方式來執行數據庫的查詢。與鏈接抓取的區別在於,一般狀況下這個SELECT語句不是當即執行的,而是在訪問到關聯對象的時候纔會執行。
   子查詢抓取(Subselect fetching)
  子查詢抓取也是指Hibernate經過另一條SELECT語句來抓取當前對象的關聯對象的方式。與查詢抓取的區別在於它所採用的SELECT語句的方式爲子查詢,而不是經過外鏈接。
   批量抓取(Batch fetching)
  批量抓取是對查詢抓取的優化,它會依據主鍵或者外鍵的列表來經過單條SELECT語句實現管理對象的批量抓取。
  以上介紹的是Hibernate 3所提供的抓取策略,也就是抓取關聯對象的手段。爲了提高系統的性能,在抓取關聯對象的時機上,還有如下一些選擇。
   當即抓取(Immediate fetching)
  當即抓取是指宿主對象被加載時,它所關聯的對象也會被當即加載。
   延遲集合抓取(Lazy collection fetching)
  延遲集合抓取是指在加載宿主對象時,並不當即加載它所關聯的對象,而是到應用程序訪問關聯對象的時候才抓取關聯對象。這是集合關聯對象的默認行爲。
   延遲代理抓取(Lazy proxy fetching)
  延遲代理抓取是指在返回單值關聯對象的狀況下,並不在對其進行get操做時抓取,而是直到調用其某個方法的時候纔會抓取這個對象。
   延遲屬性加載(Lazy attribute fetching)
  延遲屬性加載是指在關聯對象被訪問的時候才進行關聯對象的抓取。
  介紹了Hibernate所提供的關聯對象的抓取方法和抓取時機,這兩個方面的因素都會影響Hibernate的抓取行爲,最重要的是要清楚這兩方面的影響是不一樣的,不要將這兩個因素混淆,在開發中要結合實際狀況選用正確的抓取策略和合適的抓取時機。
  抓取時機的選擇
  在Hibernate 3中,對於集合類型的關聯在默認狀況下會使用延遲集合加載的抓取時機,而對於返回單值類型的關聯在默認狀況下會使用延遲代理抓取的抓取時機。
  對於當即抓取在開發中不多被用到,由於這極可能會形成沒必要要的數據庫操做,從而影響系統的性能。當宿主對象和關聯對象老是被同時訪問的時候纔有可能會用到這種抓取時機。另外,使用當即鏈接抓取能夠經過外鏈接來減小查詢SQL語句的數量,因此,也會在某些特殊的狀況下使用。
  然而,延遲加載又會面臨另一個問題,若是在Session關閉前關聯對象沒有被實例化,那麼在訪問關聯對象的時候就會拋出異常。處理的方法就是在事務提交以前就完成對關聯對象的訪問。
  因此,在一般狀況下都會使用延遲的方式來抓取關聯的對象。由於每一個當即抓取都會致使關聯對象的當即實例化,太多的當即抓取關聯會致使大量的對象被實例化,從而佔用過多的內存資源。
  抓取策略的選取
  對於抓取策略的選取將影響到抓取關聯對象的方式,也就是抓取關聯對象時所執行的SQL語句。這就要根據實際的業務需求、數據的數量以及數據庫的結構來進行選擇了。
  在這裏須要注意的是,一般狀況下都會在執行查詢的時候針對每一個查詢來指定對其合適的抓取策略。指定抓取策略的方法以下所示:
  User user = (User) session.createCriteria(User.class)
  .setFetchMode("permissions", FetchMode.JOIN)
  .add( Restrictions.idEq(userId) )
  .uniqueResult();
  5、 查詢性能提高小結
  在本小節中介紹了查詢性能提高的方法,關鍵是如何經過優化SQL語句來提高系統的查詢性能。查詢方法和抓取策略的影響也是經過執行查詢方式和SQL語句的多少來改變系統的性能的。這些都屬於開發人員所應該掌握的基本技能,避免因爲開發不當而致使系統性能的低下。
  在性能調整中,除了前面介紹的執行SQL語句的因素外,對於緩存的使用也會影響系統的性能。一般來講,緩存的使用會增長系統查詢的性能,而下降系統增長、修改和刪除操做的性能(由於要進行緩存的同步處理)。因此,開發人員應該可以正確地使用有效的緩存來提升數據查詢的性能,而要避免濫用緩存而致使的系統性能變低。在採用緩存的時候也應該注意調整本身的檢索策略和查詢方法,這三者配合起來才能夠達到最優的性能。
  另外,事務的使用策略也會影響到系統的性能。選取正確的事務隔離級別以及使數據庫

相關文章
相關標籤/搜索