2017-02-23 106 views
1

我使用Hibernate 5.2.8.Final版本,我們有一個要求,我們從數據庫讀取數百萬的數據,並通過一些業務邏輯更新數據,因爲我的數據庫是巨大的我想承諾達到我BATCHSIZE後的數據,所以我寫了下面的代碼花費很長時間沖洗中間使用休眠

Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 
session.getTransaction().begin(); 
Query<Object> query = session.createQuery(SQL, Object.class); 
ScrollableResults scrollableResults = query.setCacheMode(CacheMode.IGNORE) 
     .scroll(ScrollMode.FORWARD_ONLY); 
int count = 0; 
while (scrollableResults.next()) 
{ 
    Object object = (Object) scrollableResults.get(0); 
    process(object) 
    session.update(object); 
    if (++count % batchSizeDeclare== 0) 
    { 
     session.flush(); 
     session.clear(); 
     LOGGER.info("Updated batch records"); 
    } 
} 
session.getTransaction().commit(); 
LOGGER.info("commited in Hibernate "); 
} 

下面是我的hibernate.cfg.xml文件

<?xml version='1.0' encoding='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
     "-//Hibernate/Hibernate Configuration DTD//EN" 
     "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
    <session-factory> 
     <!-- Database connection settings --> 
     <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> 
     <property name="connection.url">jdbc:sqlserver://com;database=DEV</property> 
     <property name="connection.username">user</property> 
     <property name="connection.password">pass</property> 

     <property name="hibernate.default_schema">schema</property> 

     <!-- JDBC connection pool (use the built-in) --> 
     <property name="connection.pool_size">5</property> 

     <!-- SQL dialect --> 
     <property name="dialect">org.hibernate.dialect.SQLServer2012Dialect</property> 

     <!-- Disable the second-level cache --> 
     <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property> 

     <!-- Echo all executed SQL to stdout --> 
     <!-- <property name="show_sql">true</property> --> 
     <!-- <property name="format_sql">true</property> --> 

     <!-- Drop and re-create the database schema on startup --> 
     <property name="hbm2ddl.auto">update</property> 

     <!-- org.hibernate.HibernateException: No CurrentSessionContext configured! --> 
     <property name="hibernate.current_session_context_class">thread</property> 

     <property name="hibernate.jdbc.batch_size">100</property> 

     <property name="hibernate.c3p0.min_size">5</property> 
     <property name="hibernate.c3p0.max_size">20</property> 
     <property name="hibernate.c3p0.timeout">300</property> 
     <property name="hibernate.c3p0.max_statements">50</property> 
     <property name="hibernate.c3p0.idle_test_period">3000</property> 

     <mapping class="com.beans.Object" /> 

    </session-factory> 
</hibernate-configuration> 

下面是我Object.java

public class Object implements Serializable 
    { 
     private static final long serialVersionUID = 1L; 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     @Column(name = "ID", nullable = false, unique = true, updatable = false) 
     private int id; 
     private String filePath; 

    private String fileName; 
    private String mimeType; 
    private double fileSize; 
    // removed getters and setters 

    } 

一旦我的代碼到達session.flush(),即使在等待30分鐘後它也沒有做任何事情。這是批量提交的正確方法嗎?如何批量更新?

+0

batchSizeDeclare的值是什麼? – Thierry

+0

100是我的batchSizeDeclare值 – rajadilipkolli

回答

0

當我的代碼到達session.flush後,它在等待30分鐘後甚至沒有做任何事情,即使是 。

恰恰相反!數據庫做得太多了。只是你沒有看到任何進展,因爲數據庫正在努力應對你提交的大量工作。

這是批量提交的正確方法嗎?

簡短的回答是沒有

正如我在文章14 High-Performance Java Persistence Tips中所解釋的那樣,您不必從數據庫中獲取數百萬行。你有更好的選擇:

  1. 你可以做加工在數據庫中,這樣你不支付提取數據併發送它在網絡上,只處理它在Java中的價格。
  2. 如果無法在DB <中處理它,則需要使用批處理器,該處理器一次只能獲取小塊數據。這樣,您甚至可以並行處理批處理,這會減少整體處理時間。

解決這個問題的唯一方法就是改變你的方法。

+0

還有一個問題,我已將batchSizeDeclare變量設置爲100,這是hibernate.cfg.xml文件值中的批量更新大小。對於100條記錄將花30分鐘以上,我也看到聲明id值作爲序列是最好的。更改值有助於提高性能 – rajadilipkolli

+0

記錄SQL查詢並確保僅執行100個條目。檢查數據庫日誌以查看發生了什麼也很重要。 –

+0

在SQL查詢中,它只顯示100個數據庫,在db日誌中插入另一批數據,其中還包含1000萬條插入數據塊的記錄數據 – rajadilipkolli