2010-08-12 54 views
3

我有一個程序逐行讀取文本文件,並從每行創建一個Hibernate實體對象,並將它們保存。我有幾個這樣的文本文件要處理,每個文件都有大約30萬行。我發現我目前的執行速度非常慢,而且我想知道是否有任何事情可以改進。快速批量保存Hibernate的方法?

我的主要方法,通過線處理文本文件行,像這樣:

// read the file line by line 
FileInputStream fileInputStream = new FileInputStream(new File(fileName)); 
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); 
BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
int lineCount = 0; 
String line = bufferedReader.readLine(); 
while (line != null) 
{ 
    // convert the line into an Observations object and persist it 
    convertAndPersistObservationsLine(line); 

    // if the number of lines we've processed has built up to the JDBC batch size then flush 
    // and clear the session in order to control the size of Hibernate's first level cache 
    lineCount++; 
    if (lineCount % JDBC_CACHE_SIZE == 0) 
    { 
     observationsDao.flush(); 
     observationsDao.clear(); 
    } 

    line = bufferedReader.readLine(); 
} 

的convertAndPersistObservationsLine()方法只是拆分文本行成標記,創建一個新的實體對象,從數據填充實體的領域令牌,然後通過調用Hibernate的Session.saveOrUpdate()方法的DAO保存對象。 DAO方法flush()和clear()是直接調用相應的Hibernate Session方法。

Hibernate屬性'hibernate.use_second_level_cache'設置爲false,並且Hibernate屬性'hibernate.jdbc.batch_size'設置爲50,Java常量JDBC_CACHE_SIZE也是如此。

有人可以提出一個更好的方法來解決這個問題,或者對上面的任何調整都可以提高這個批量加載程序的性能嗎?

在此先感謝您的幫助。

- 詹姆斯

+2

你有正確設置交易,沒有自動提交等?你的dao不會意外刷新會話持續嗎?你能分析代碼,看看大部分時間都花在哪裏嗎?你能否啓用sql日誌來驗證沒有中間刷新? – 2010-08-12 16:31:50

+0

是否最好將Hibernate屬性'hibernate.connection.autocommit'設置爲false(默認情況下該值爲true)?我的DAO不會調用flush(),只會在返回前調用saveOrUpdate()。我還沒有分析代碼,也沒有監視中間沖洗的日誌,感謝這些建議。 – 2010-08-12 16:47:19

+0

亞當我建議看一下由hibernate和spring生成的日誌,以查看插入過程中發生了什麼;我認爲無論是Spring還是Hibernate都會在事務中禁用自動提交(使設置無關緊要,但您應該確認)。 – 2010-08-12 18:10:36

回答

3

有幾件事情:

  1. 你可以量化 「速度奇慢」?你實現每秒插入多少個插入點?你認爲你應該有什麼比率?數據庫本身是什麼類型的負載?其他人是否同時從桌上讀書?

  2. 如何連接到數據庫?所有這一切發生在單個事務中重新使用相同的連接?

  3. 您是否有機會使用identity標識符?本細則規定,JDBC batching is disabled silently if you are

,Hibernate在JDBC級別的關閉插入配料透明的,如果你使用的身份標識符生成。

+0

感謝您的迴應,馬特。 1.它看起來像我每秒大約4插入。我能期望大幅改善這一點嗎? 2.我的DAO對象包含一個SessionFactory對象,它通過Spring依賴注入進行連接。我使用的SessionFactory類是org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean。我使用的事務管理器類是org.springframework.orm.hibernate3.HibernateTransactionManager,我在Spring應用程序上下文配置文件中啓用了基於註釋的事務行爲。 – 2010-08-12 16:27:55

+0

DAO類將此作爲事務性設置: @Transactional(propagation = Propagation.REQUIRED,readOnly = false,isolation = Isolation.DEFAULT) SessionFactory具有DataSource屬性,並且這是在Spring應用程序上下文中配置的URL,用戶/密碼,驅動程序類的正常設置等。 3.我認爲我沒有使用身份標識符,但實體類的ID字段如下所示: @Id @Column(name =「ENTITY_ID」) @GeneratedValue(strategy = GenerationType.AUTO) public T getId() { return id; } – 2010-08-12 16:33:39

+0

對於沒有格式化上述評論,我表示抱歉 - 我嘗試使用基本的HTML和Markdown,但從未能夠獲取任何內容,並始終以一個運行字符串結尾。 – 2010-08-12 16:39:53

8

代碼本身和Hibernate配置看起來是正確的(正確的我的意思是它們遵循文檔中的batch insert習語)。但是,這裏有一些額外的建議:

如前所述,使絕對確定您沒有使用ID生成器,如IDENTITY擊敗批處理。當使用GenerationType.AUTO時,持久性提供者將根據數據庫選擇合適的策略,因此,根據數據庫的不同,您可能必須更改TABLESEQUENCE策略(因爲Hibernate可以使用hi-lo算法緩存ID )。

還要確保Hibernate按預期進行批處理。爲此,請激活日誌記錄並監視BatchingBatcher以跟蹤正在執行的批處理的大小(將被記錄)。

在你的特殊情況下,你可能會考慮使用the StatelessSession interface(當然問題一旦解決)。