Hibernate批處理操作最佳化 (批量插入、更新與刪除)

來源:互聯網
上載者:User

標籤:http   io   os   使用   java   ar   strong   for   檔案   

問題描述
  1. 我開發的網站加了個新功能:需要線上上處理表資料的批量合并和更新,昨天下午發布上線,執行該功能後,伺服器的load突然增高,變化曲線異常,SA教育了我一番,讓我儘快處理,將CPU負載降低。

  2. 工作所需,我經常要寫些程式批量處理資料,每次執行幾十萬資料處理的時候,我機子的CPU都會飆高,而且資料處理速度會越來越慢。比如第一個1W條要5分鐘,第二個1W條就要10分鐘,要幹其他事情的時候機子也卡的不行,只能等著處理完資料。

其實我一直認為是資料量太大,從來不認為是程式問題,所以一直沒怎麼關注過。這次問題浮上表面,所以要好好解決下!

 

產生原因

主要原因:Hibernate的一級緩衝影響。

我們每次儲存的東西都會儲存在Session緩衝中,這就是Hibernate的一級緩衝,如果我們一直迴圈執行save等操作,緩衝裡東西會越來越多,速度也就越來越慢,伺服器一直在迴圈處理,自然也會增加負載。

這本來就是Hibernate不擅長的地方,而且一級緩衝不可以不用,如果我們要儲存的資料量十分巨大,那麼在程式中執行添加、更新方法時,Session對象自身開闢的一級緩衝會不斷消耗,直至OutOfMemoryError (記憶體溢出異常)。

這就需要我們管理好Hibernate的緩衝,或者不使用Hibernate。

 

解決方案

批量插入最佳化

1、仍舊用Hibernate API來進行批處理,但在一定的量的時候,及時的清除緩衝。

1)最佳化Hibernate,在設定檔中設定hibernate.jdbc.batch_size參數,來指定每次提交SQL的數量。配置hibernate.jdbc.batch_size參數的原因就是盡量少讀資料庫,hibernate.jdbc.batch_size參數值越大,讀資料庫的次數越少,速度越快。

<!--設定hibernate.jdbc.batch_size參數--><hibernate-configuration>    <session-factory>        .........        <property name="hibernate.jdbc.batch_size">50</property> ......... <session-factory><hibernate-configuration>

 

2)程式及時清除緩衝,即每插入一定量的資料後及時把它們從內部緩衝中清除掉,釋放佔用的記憶體。 Session實現了非同步write-behind,它允許Hibernate顯式地寫操作批處理

範例程式碼:

// 每處理50條清空緩衝session.save(myObject);if (i/50 == 0) { session.flush(); session.clear();}// 在我的項目中寫法如下:if (i/50 == 0) { this.getHibernateTemplate().flush(); this.getHibernateTemplate().clear();}

 

2、通過JDBC API來做批量插入,繞過Hibernate API。這個方法效能上是最好的,也是最快的。

範例程式碼:

String insertSql = "insert into user(name,address) values(?,?)";Session session = getHibernateTemplate().getSessionFactory().openSession();Connection conn = session.connection();PrepareStatement stmt = conn.prepareStatement(insertSql);// 方式1:自動認可conn.setAutoCommit(true);for(int i = 0; i++; i<10000) { stmt.setString(1, "testName"); stmt.setString(2, "testAddress"); stmt.execute();}// 方式2:批量提交conn.setAutoCommit(false);for(int i = 0; i++; i<10000) { stmt.setString(1, "testName"); stmt.setString(2, "testAddress"); stmt.addBatch(); if (i % 100 == 0) { stmt.executeBatch(); conn.commit(); }}stmt.executeBatch();conn.commit();// 關閉sessionsession.close();

 

附測試資料:

// 測試方法:迴圈插入10000條資料,拆分10頁,每頁1000條。// 直接Hibernate的save()方法,不做任何處理。page 0 process time : 5925page 1 process time : 6722page 2 process time : 8019page 3 process time : 9456page 4 process time : 10263page 5 process time : 11511page 6 process time : 12988page 7 process time : 13969page 8 process time : 15196page 9 process time : 16820// Hibernate的save()方法,但每1個清除緩衝。page 0 process time : 10257page 1 process time : 10709page 2 process time : 11223page 3 process time : 10595page 4 process time : 10990page 5 process time : 10222page 6 process time : 10453page 7 process time : 10196page 8 process time : 9645page 9 process time : 10295// Hibernate的save()方法,但每50個清除緩衝。page 0 process time : 5848page 1 process time : 5480page 2 process time : 5739page 3 process time : 5960page 4 process time : 6287page 5 process time : 5947page 6 process time : 7012page 7 process time : 6235page 8 process time : 6063page 9 process time : 6055// JDBC的auto commit 方式page 0 process time : 840page 1 process time : 800page 2 process time : 800page 3 process time : 847page 4 process time : 806page 5 process time : 829page 6 process time : 1042page 7 process time : 893page 8 process time : 857page 9 process time : 854// JDBC的batch方式,每50個commitpage 0 process time : 827page 1 process time : 801page 2 process time : 918page 3 process time : 828page 4 process time : 856page 5 process time : 831page 6 process time : 815page 7 process time : 842page 8 process time : 817page 9 process time : 937

 

經測試:

1)若直接使用Hibernate,處理同樣資料的時間會遞增,甚至成倍增加,而且在測試過程中CPU使用率一直在70%上下。

2)若在使用Hibernate中每save一次都清空緩衝的話,雖然時間不會遞增,但處理速度很慢。在本例中採用每50個清空一次緩衝較為合適,實際應用視情況而定。一定量的時候清空緩衝,雖然速度上沒有提升,但會比較穩定,不會隨著時間陡增,而且測試中CPU使用率也維持在20%上下,可以挽救一點效能損失,使系統相對穩定。

3)若使用JDBC API,不論auto commit方式還是batch方式,相比Hibernate在效能上都有近10倍的提升。不過在資料量較大的時候,推薦使用batch方式。

批量更新刪除最佳化

Hibernate2中,對於批量更新/刪除操作,都是先將符合要求的資料查出來,然後再做更新/刪除操作。這樣一來會佔用大量記憶體,而且海量資料處理的時候效能很低。

而Hibernate3對批量更新/刪除提供了支援,能夠直接執行批量更新批量刪除語句,無需把被更新刪除的對象先載入到記憶體中,類似於JDBC的批量更新/刪除操作

不過對於迴圈處理資料更新刪除情境,建議還是使用JDBC,方法同上:批量插入的方法2。

 

(轉自:http://www.verydemo.com/demo_c146_i31256.html)

Hibernate批處理操作最佳化 (批量插入、更新與刪除)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.