2016-05-31 51 views
2

我想多線程的結果集。我想確保每當我在其中一個線程中調用next()時,所有其他線程都被鎖定。這很重要,因爲如果許多線程同時調用next()方法,這將導致跳過行。這是我做的同步鎖定結果集對象嗎?

public class MainClass { 
    private static ResultSet rs; 

    public static void main (String [] args) { 

     Thread thread1 = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       runWhile(); 
      }}); 
     Thread thread2 = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       runWhile(); 
      }}); 

     thread1.start(); 
     thread2.start(); 
     thread1.join(); 
     thread2.join(); 

     System.exit(0); 
    } 

    private static void runWhile() { 
     String username = null; 
     while ((username = getUsername()) != null) { 
      // Use username to complete my logic 
     } 
    } 

    /** 
    * This method locks ResultSet rs until the String username is retrieved. 
    * This prevents skipping the rows 
    * @return 
    * @throws SQLException 
    */ 
    private synchronized static String getUsername() throws SQLException { 
     if(rs.next()) { 
      return rs.getString(1).trim(); 
     } 
     else 
      return null; 
    } 
} 

這是使用​​的正確方法。它鎖定ResutSet並確保其他線程不會干擾?

這是一個很好的方法嗎?

+3

我將有一個線程讀取ResultSet將任務添加到ExecutorService。 –

+0

謝謝。我有一種感覺,我的方法是錯誤的。雖然它有效,但它感覺不對 –

+0

它會以這種方式工作。但訂單不能保證。 – gba

回答

5

JDBC對象不應該在線程之間共享。這適用於連接,語句和結果集。這裏最好的例子是JDBC供應商遵循規範並進行內部鎖定,這樣你就可以解決這個問題,在這種情況下,所有線程仍然試圖獲得相同的鎖,並且一次只能有一個進程。這將比使用單個線程慢,因爲除了從數據庫中讀取相同的內容之外,管理所有線程還有額外的開銷。 (由驅動程序完成的鎖定可能是爲了驅動程序的利益,因此提供程序不必處理由於用戶濫用其軟件而導致的競爭狀態的錯誤報告,它鎖定並不一定意味着軟件實際上應該被多個線程使用。)

線程可以同時取得進展時,多線程工作,請參閱Amdahl's Law。如果您有一種情況,您可以閱讀ResultSet並使用結果來創建您提交給ExecutorService的任務(如Peter Lawrey在評論中所建議的那樣),那麼這會更有意義(只要這些任務可以獨立工作並且不會不必等待)。

0

我會建議創建ResultSet,然後將所有數據複製到DTO(數據傳輸對象)或DAO(數據訪問對象)中。在DTO或DAO上有數據後,關閉你的ResultSet,Statement和Connection。

的結構很簡單,創造一個DTO/DAO存儲在訂單記錄,其字段和解析能力是這樣的:

ArrayList<HashMap<String, Object>> table = new ArrayList<HashMap<String, Object>>(); 
HashMap<String, Object> record = new HashMap<String, Object>(); 
String field1 = "something"; 
Integer field2 = new Integer(45); 
record.put("field1", field1); 
record.put ("field2", field2); 
table.add(record); 

你可能(或許應該)實現自動化,使DTO/DAO足夠靈活,可以在任何表中使用相同的類,而不需要硬編碼或固定名稱。

請記住,您將需要創建一個包裝和存儲/讀取數據的方法,並且這些方法應該是線程安全的。

請記住,只有您有足夠的內存來存儲ResultSet的所有記錄時,此設計纔有效。