2009-08-01 13 views
3

Ich habe ein Programm, das eine Datenbank in einem bestimmten Intervall abfragen muss und mit den Datensätzen, die es ruft, eine Aktion ausführen und dann die Tabelle erneut aktualisieren.JDBC und Threading

Ich benutze den ExecutorService, um die Threads auszuführen, aber wundere mich, sollte jeder Thread eine eigene Verbindung erhalten (weil es Datenbank aktualisieren muss) oder kann ich die gleiche Verbindung verwenden, die ich verwendet, um die ersten Ergebnisse abzufragen?

Kann Verbindung Pooling arbeiten, bin auf Oracle 9i.

Antwort

10

Sie sollten immer eine separate Verbindung für separate Threads verwenden, da die Treiber auf diese Weise nicht Thread-sicher sind. Ein Verbindungspool könnte Ihnen helfen, da er die Wiederverwendung von Verbindungen auf sichere Weise ermöglicht.

Sie könnten auch ein Abfrage-Dispatch-Muster erstellen - wenn ich Ihr Problem richtig verstehe -, wo ein Thread für die Abfrage und Starts von N Threads verantwortlich ist, die die Datenbank aktualisieren können - die alle separate Verbindungsobjekte haben.

Sie können auch ein Batch-Update über das PreparedStatement betrachten zu tun, so Fäden auf sich in Bezug auf den Zeilen- und Tabellensperren stolpern nicht, die folgende Struktur verwendet:

  • 1 Abfrage Thread
  • NCPU Verarbeitungsthreads
  • 1 Batch-Update-Thread

wie ein Mini-db gabel verbinden.

bearbeiten

Beispiele, wie man mit Pstmt Batch-Update zu tun:

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(); 

Oder Sie eine Warteschlange in der Schleife nicht abfragen, wo die Update-Anfragen von den Verarbeitungsthreads ankommen:

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

Danke !!! Ich habe einen Abfragethread und N Threads für die Verarbeitung. Wie kann ich eine Batch-Aktualisierung mithilfe einer vorbereiteten Anweisung durchführen? – Ngetha

+0

Danke, das funktionierte perfekt für mich – Ngetha

+0

@Ngetha: Wenn dies Ihre Frage beantwortet, * akzeptieren * die Antwort: http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work (Das gleiche gilt für Ihre anderen Fragen.) –

2

Wenn Sie den Code für die Oracle JDBC OracleConnection und OraclePreparedStatement betrachten, m Die wichtigsten Methoden sind synchronisiert, so dass sie "threadsicher" sind. Die Verwendung einer einzelnen Connection über mehrere Threads hinweg bietet Ihnen nicht die größte Effizienz, da jeder Thread auf die Operationen der Connection und PreparedStatement (insbesondere execute) warten muss, bevor er seine eigenen Aktionen ausführt.

+1

@akf: Während die Frage speziell Oracle 9i erwähnt, ist es keine gute Idee, sich auf implementierungsspezifisches Verhalten zu verlassen. Natürlich gibt es keine Garantie dafür, dass die JDBC-Stacks anderer Hersteller Threadsafe sind. AFAIK, wird von den JDBC-Spezifikationen nicht benötigt. –

+0

@Stephen C, guter Punkt. – akf

+0

Sie können den PreparedStatement-API-Thread nicht sicher machen. Sie können es nicht threadsicher machen, indem Sie alle Methoden synchronisieren. Es ist eine Stateful API. Die API müsste neu gestaltet werden, um einen generellen und sicheren Zugriff auf PreparedStatement-Instanzen über Threads hinweg zu ermöglichen. –