2009-08-25 54 views
1

我正在開發一個應該接收來自數百個業務部門的夜間報告的服務器。報告目前是加密的csv文件。這些報告總共應該每天保存在數據庫中以供日後使用,其數量應達到50萬到100萬條。如何在併發批處理中繞過JDBC語句緩存?

我爲每個傳輸創建了一組PreparedStatements。這些語句用於在執行和提交之前批量處理50條記錄。每個記錄可能會導致多達20個數據庫插入。當傳輸排隊並逐個處理時一切正常。

因爲我試圖同時做到這一點,我注意到不同的線程得到了完全相同的PreparedStatements實例。這引起了以下問題

  1. 多個線程添加語句到同一批次當任何線程決定是時候這樣做
  2. 提交被調用時數據庫沒有達到它的
  3. 批次正在執行約束一些線程還沒有來得及使用某些語句

的問題是:是那裏是要創建一種強制一份聲明而不是重用現有從語句緩存?

如果不是有沒有更好的方式來處理比

  • 創建不具有語句/連接池
  • 從數據庫中取消約束批次單獨的數據源的情況;插入順序也沒有什麼關係了
  • 迫使順序處理

編輯:試圖澄清這一問題

要有線程T1和T2。 讓我們準備好陳述S1和S2。 讓批次B1和B2。

每次使用S1時,都將其添加到B1中。每次使用S2時,它都被添加到B2中。 提交時,必須在每個外鍵約束S2之前提交S1。當

  • T1處理傳輸興高采烈
  • T2處理傳輸發生

    問題無辜

  • T1使用語句S1添加S1A到含有批量B1 S1A
  • T1使用語句S2添加S2A批量B2包含s2a
  • T1決定是時候提交
  • T1提交batch B1 contai寧S1A
  • T2使用S1添加S1b到含有批量B1 S1B
  • T2使用S2添加含有S2A S2B到批次B2,S2B
  • T1提交批處理B1 containting S2A,S2B
  • 數據庫說 '否'因爲s2b是在外鍵禁止的s1b之前提交的。

這可以避免與手動同步以及指出的答案,但然後我仍然需要分別跟蹤每個批次的大小,而不是應用每個線程的本地邏輯。

+0

您必須使用供應商特定的方法來執行您所需的操作。你在使用哪種RDBMS? – Juris 2009-08-25 11:41:01

+0

Aww。這真的不是我想聽到的。目前該測試系統在Apache Derby上運行。生產數據庫將是Oracle 10g或R – 2009-08-25 11:54:47

+0

我會給予兩個答案upvote,因爲他們幫助我考慮了我的問題。我會提供我在設法測試時選擇的解決方案。 – 2009-08-26 04:24:11

回答

0

我目前的解決方案是停止擔憂,並開始愛上共享批次。我已在處理算法分爲兩個階段

  1. 解析一組N個記錄,並將其設定的N個記錄保存在intermidiate格式
  2. 堅持爲批處理時,鎖被授予當前線程

這允許解析併發和按順序分批。我只需要找到一個最佳位置來減少線程之間的等待時間。

對甜蜜點的追求可能會導致實現某種雙相鎖定方案,即讓每個線程按照自己的意願執行,並在提交時確保所有線程在實際批處理執行之前完成其當前記錄。

在後一種解決方案中,可能需要對每個PreparedStatement的參數設置進行同步,儘管我沒有測試過是否會導致任何問題。這應該。

1

您是否試圖在單個連接實例中使用多個語句?國際海事組織(IMO)建議爲您描述的行爲建立連接池。另一種方法是手動同步。

+0

謝謝你的回答。 每個線程都有一個連接。每個連接都有多個語句,每個單獨的SQL語句都有一個PreparedStatement實例。每個語句都包含一個批次。 問題是,由於語句緩存,每個線程沒有一個唯一的語句集,導致批處理問題。 連接池和語句緩存在這裏並沒有什麼幫助,因爲連接和語句準備事件很少。 – 2009-08-25 10:06:12

+0

仍然試圖理解這個問題 - 這個問題的執行順序是什麼? – Everyone 2009-08-25 10:59:06

+0

我編輯了問題(希望),以方案的一些澄清。執行順序導致崩潰,是的。另一方面,共同的聲明和批次使得不可能信任當地的國家。在我看來,這在我的方案中引起了可避免/非有利的併發,即將批量與實際工作線程分開管理。 – 2009-08-25 11:29:50

1

該解決方案是供應商特定的。

如果您的代碼在servlet下運行,那麼您可以通過在Web應用程序中配置數據源來解決您的問題。我已經使用Tomcat下的Oracle驅動程序完成了這項工作,但我確信其他應用程序服務器具有類似的配置連接池的方法。

如果您的代碼是獨立的,那麼您必須使用供應商特定的API。正如你將針對Oracle用作生產數據庫,這裏是爲Oracle JDBC驅動程序一個簡單的例子:

import oracle.jdbc.OracleConnection; 

... 

public static void disableStatementCaching(java.sql.Connection conn) 
     throws SQLException { 
    ((OracleConnection)conn).setImplicitCachingEnabled(false); 
} 

... 

欲瞭解更多信息,請參閱JDBC dev guide甲骨文10.2

+0

謝謝你的回答。即使我對使用它們持懷疑態度,我也一定會看看供應商特定的API。 該應用程序不作爲servlet運行。它作爲EJB3 @WebService -annotation定義的Web服務發佈。但是,使用應用程序服務器定義的數據源並對其進行配置是完全可能的。它只需要適當的文檔,這可能會導致未來開發人員決定通過啓用語句緩存來優化性能。 – 2009-08-26 04:21:13