2014-05-20 6 views
5

Ich habe einen Block von Code, der Datensätze in einer Datenbank aktualisiert. Reduziertes Beispiel:Kann ich PreparedStatement erneut verwenden, wenn eine vorübergehende Ausnahme auftritt?

... 
statement = connection.prepareStatement(
    "INSERT INTO thistable (name) VALUES (?)", 
    PreparedStatement.RETURN_GENERATED_KEYS 
); 
statement.setString(1, "Fred"); 
statement.addBatch(); 
statement.setString(2, "Joe"); 
statement.addBatch(); 
statement.executeBatch(); 
... 

Dieser Teil von Code ist die verarbeitet ein viel von Datensätzen, und der Code eine Menge Threads für Geschwindigkeit läuft. Das ist alles in Ordnung, aber als die Last in der Live-Umgebung steigt, habe ich bemerkt, dass ein paar SQLTransientException s geworfen werden. Es scheint, dass ich nichts dagegen tun kann, außer die Transaktion erneut zu versuchen.

Meine Frage ist: Könnte der Stapel gelöscht worden sein, obwohl die Anweisung fehlgeschlagen ist? Bin ich OK, einfach die executeBatch Zeile erneut zu versuchen, oder muss ich den gesamten Stapel neu erstellen? Und ist das für Nicht-Batch-Anweisungen das gleiche?


Kurz gesagt und allgemein, ist dies eine gute Möglichkeit, vorübergehende Ausnahmen zu behandeln?

statement.setString(1, "Fred"); 
statement.addBatch(); 
statement.setString(2, "Joe"); 
statement.addBatch(); 
for(int attempt = 0; ; attempt ++) { 
    try { 
     statement.executeBatch(); 
     break; 
    } catch(SQLTransientException ex) { 
     if(attempt >= 3) { 
      throw ex; 
     } 
     try { 
      Thread.sleep(attempt * attempt * 100); 
     } catch(InterruptedException ex2) { 
      throw ex; 
     } 
    } 
} 
+0

Ich habe diese Frage mit MySQL getaggt, weil wir sie gerade verwenden, aber ich möchte das Standardverhalten und nicht das implementierungsspezifische Verhalten verstehen, da wir bald auf Postgres migrieren werden. – Dave

+0

Theoretisch sollte 'SQLTransientException' nur ausgelöst werden, wenn der Fehler Operationen zulässt, die ohne" ohne Eingreifen der Funktionalität auf Anwendungsebene "wiederholt werden können. –

+0

Haben Sie einen SQL-Status für diese Ausnahme (getSQLState())? – Mani

Antwort

2

Da die API liefert keine viel Informationen über das Verhalten, wenn SQLTransientException von geschieht auseinander unten

when the driver has determined that the timeout value that was specified by the 
setQueryTimeout method has been exceeded and has at least attempted 
to cancel the currently running Statement 

die Mysql JDBC4 Umsetzung bestätigt.

In meiner Beobachtung konnte ich sehen, eine mögliche dort SQLTimeoutException ist (das heißt SQLTransientException) passieren kann, wenn die Zeitüberschreitung.

Und während Zeitüberschreitung, ist es nicht nur die letzten Aussagen löscht, wird es gesamtes Batch Clearing (zumindest in MYSQL Implementation)

// we timeout the entire batch, not individual statements 

so dass ein Teil klar.

Und per JDBC-Spezifikation

The statement’s batch is reset to empty once executeBatch returns 

Unabhängig von executeBatch Ausnahme auslöst/gelingt es der Ansatz klar würde.

Insbesondere Mysql Prepared Statement löscht die Charge bei finaly Block in executeBatch() -Methode

finally { 
     this.statementExecuting.set(false); 
     clearBatch(); 
     } 

So Ihre Logik wird nicht funktionieren, da Sie nicht wieder die Aussagen in Batch-Zugabe werden.

Fügen Sie die Anweisungen also zurück zum Stapel und führen Sie sie erneut aus. Es besteht die Möglichkeit, dass Sie wieder in Timeout landen. Also finde zuerst die Auszeit. wenn möglich, schreiben Sie einige Informationen über Ursache/Zustand in die Ausführungsprotokolle.

+0

Manuelles Löschen (nur für den Fall) und erneutes Befüllen ist dann. Es ist schade - ich hatte gehofft, dass dies in einer Methode versteckt werden könnte. – Dave

+0

Nur um (für zukünftige Besucher) hinzuzufügen, dass für die verwandte Frage zu Nicht-Batch-Anweisungen die Werte nicht erneut ausgefüllt werden müssen, gemäß dieser Dokumentation: http://docs.oracle.com/javase/7/ docs/api/java/sql/PreparedStatement.html # clearParameters() – Dave

0

Was ist die Ausnahmebedingungsnachricht? Nicht sicher, ob es aufgrund eines MySQL-Verbindungsproblems fehlgeschlagen ist. Außerdem finde ich es nicht gut, eine lange Anfrage zu bearbeiten. Sie können es mehrmals ausführen, indem Sie Stück für Stück laufen, um Ihr Ziel zu erreichen.

+0

Beantwortet das in den Kommentaren zu der Frage. Zukünftig sollten Sie keine Kommentare/Fragen als Antworten veröffentlichen. – Dave

Verwandte Themen