2009-07-29 93 views
2

我有一個Java JDBC應用程序,它使用多個線程從Oracle數據庫檢索信息。每個線程si應該定期執行一條語句,該語句在特定的表上執行一個選擇(每個表的表不同)。關閉JDBC不需要的語句

線程是擴展Thread類的類的實例。該類有一個私有變量,用於存儲與數據庫的連接。該線程還有一個子線程,通過語句定期從表中刪除一些信息。當我運行一個單線程(從單個表中獲取數據)它完美的作品,但是當我運行多個線程(試圖從多個表中獲取數據)時,我得到一個錯誤,說我的語句在我之前關閉打印由該語句生成的整個結果集。

我的問題是:

爲什麼不同的線程結束我的發言? 爲什麼子線程不關閉父線程語句? 我能做些什麼來防止這種情況發生?

我希望有人能幫忙。 Constantin

我不使用連接池,因爲每個線程上的連接都會永久保持打開狀態,因爲我每20毫秒執行一次select語句,並且cild線程(擁有自己的連接)每隔10秒執行一次delete語句。

我不能將數據存儲在數組中,因爲就像我檢索它時一樣,我必須將它發送到一個用於處理的API。

我無法理解它。每個線程都是一個不同的實例(具有不同的參數,除用於連接aka用戶,密碼的那些參數外)(女巫沒有任何靜態內容)並關閉了其他語句。

每個線程都有它自己的連接對象,它有自己的語句和結果集對象。它應該是線程安全的

下面是一個代碼示例

stmt = conn.createStatement(); 
rs = stmt.executeQuery(query); 
while (rs.next()) { 
//some processing 
} 
stmt.close(); 

的conn變量是一個連接,並在thrad的構造函數創建,可這是什麼問題?

新的編輯

我都包裹着我的連接對象在wraper類和擴展成絲束不同的連接包裝類,一個是使用的線程執行SELECT語句和一個由線程執行delete語句。 我沒有關閉我的連接後的聲明,因爲它會效率低下,但我做了關閉 我沒有任何共享對象之間的線程,因爲我不需要任何。每個線程使用不同的語句對象和不同的結果集從不同的表中選擇數據,並將其傳遞給API。 要使用連接池將meam重新思考我的整個應用程序,但如果沒有其他解決方案apears比我不得不這樣做。

感謝您的幫助和抱歉,如果如果你確保你沒有線程之間共享狀態我聽起來stubern和抱歉,沒有從一開始就

+1

如果您每20毫秒運行一次查詢,那麼您應該明確地使用連接池。連接池的作用是保持連接打開。當你需要連接時調用getConnection()並且在你完成它時調用conn.close()。不要自己管理連接,因爲當您看到現在連接時,您將不得不面對管理難題。 – 2009-07-29 12:27:18

+0

如果「每個線程都有它自己的連接對象,並且它有自己的語句和結果集對象」,那麼也許你認爲發生的並不是真正發生的事情。 – 2009-07-29 12:34:36

+0

連接對象是不是線程中的靜態字段?如果其他線程無法看到它,則沒有明顯的理由關閉您的語句。 – akarnokd 2009-07-29 12:36:01

回答

3

表達我自己更清楚,你就不用再擔心同步。

  1. 使用連接池。在執行每個數據庫語句之前,從池中檢索連接。即使您每秒獲取並釋放連接50次,連接到數據庫的連接仍會保持池打開狀態,並且只有當多個線程同時需要數據庫連接時才需要新的連接。我建議你看看DBCP,它有一個強大的,線程安全和靈活的數據庫連接池的良好實現。
  2. 使用局部變量來確保連接的範圍意味着它只對當前線程可見。
  3. 當您完成數據庫語句執行時,始終關閉連接(或將它們釋放回池)。使用JDBC代碼的finally塊來完成此操作。
  4. 當再次創建語句時,請確保它們是本地的,以便它們的作用域僅對當前線程可見。
  5. 當你在finally塊中完成它們時,總是關閉語句
public Data getMyData() { 
    Connection conn = null; 
    Statement statement = null; 
    try { 
     conn = ConnectionPool.getConnection(); 
     statement conn.prepareStatement("select mydata from mytable"); 
     //execute statement, get results 
     //return Data 
    }finally{ 
     if (statement != null) statement.close();   
     if (conn != null) conn.close(); //release the connection back to the pool 
    } 
} 

只要你的連接池是線程安全的,這段代碼也應該是線程安全的,你永遠不會共享線程之間的連接或語句。

0

如果我真的絕望了,我想嘗試以下調試問題:

首先,我要創建JDBC連接對象的包裝類。每個包裝方法都會將當前線程指針與上次操作的線程指針進行比較。如果它們相同,則調用包裝連接。否則,它會記錄一個錯誤,用堆棧跟蹤來準確顯示調用的地方。

接下來,我會找到創建JDBC連接的所有位置,並將它們更改爲用包裝類的實例包裝連接。

最後,我會運行應用程序,並設置一些東西來觀察日誌。