2009-08-01 50 views
3

我有一個程序,需要在給定的時間間隔內查詢一個數據庫,並用它獲得的記錄調用執行某個動作,然後再次更新表。我正在使用ExecutorService來運行線程,但我想知道,每個線程應該獲得自己的連接(因爲它需要更新數據庫),或者我可以使用我用來查詢初始結果的同一個連接嗎?JDBC和線程

可以連接池工作,在Oracle 9i上。

回答

10

對於單獨的線程,您應該總是使用單獨的連接,因爲驅動程序在這種方式下不是線程安全的。連接池可以幫助您,因爲它可以以安全的方式重新使用連接。

如果我正確理解您的問題,您也可以執行查詢分派模式,其中一個線程負責查詢並啓動N個可能更新數據庫的線程 - 所有這些線程都有單獨的連接對象。

你也可以考慮通過做PreparedStatement的批量更新,所以線程不會在行和表鎖的條款對對方絆倒,採用以下結構:

  • 1查詢螺紋
  • NCPU處理線程
  • 1批量更新線程

就像一個小型數據庫的fork-join。如何做批量更新與數PreparedStatement pstmt

編輯

例子:

PreparedStatement pstmt = connection.prepareStatement(
    "UPDATE table SET field=? WHERE id=?"); 
for (int i = 0; i < 100; i++) { 
    pstmt.setInt(1, i * i); 
    pstmt.setInt(2, i); 
    pstmt.addBatch(); 
} 
pstmt.executeBatch(); 
pstmt.close(); 

或者你可以在環路,將更新請求從處理線程到達查詢隊列:

class WhatToUpdate { 
    public int id; 
    public int value; 
} 
Queue<WhatToUpdate> queue = new LinkedBlockingQueue<WhatToUpdate>(); 

PreparedStatement pstmt = connection.prepareStatement(
    "UPDATE table SET field=? WHERE id=?"); 

int poisons = THE_NUMBER_OF_PROCESSING_THREADS; 
while (true) { 
    WhatToUpdate record == queue.take(); 
    if (record == null) { // poison pill 
     if (--poisons <= 0) { 
      break; 
     } 
    } 
    pstmt.setInt(1, record.value); 
    pstmt.setInt(2, record.id); 
    pstmt.addBatch(); 
} 
pstmt.executeBatch(); 
pstmt.close(); 
+0

謝謝! 我有一個查詢線程和N個線程進行處理。我如何使用準備好的語句進行批量更新? – Ngetha 2009-08-01 07:28:43

+0

謝謝,這對我很好用 – Ngetha 2009-08-04 05:18:04

2

如果您查看Oracle jdbc OracleConnectionOraclePreparedStatement的代碼,請將m許多重要的方法是同步的,所以它們是'線程安全的'。在多個線程中使用單個Connection不會給您最大的效率,因爲在執行自己的操作之前,每個線程都需要等待ConnectionPreparedStatement(特別是execute)的操作完成。