Aktualisieren Sie mehr als eine Zeile atomar
Frage
Ich brauche eine Auswahl auszuführen und dann einige der Zeilen in den ResultSet
in einer atomaren Weise zu aktualisieren.
Der Code Ich bin mit Aussehen wie (vereinfacht):
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT ...");
while (rs.next()) {
if (conditions_to_update) {
rs.updateString(...);
rs.updateRow();
}
}
- Kann ich garantieren, dass der Updates atomar ausgeführt werden werden? Wenn nicht, wie kann ich versichern?
- Was passiert, wenn ein anderer Prozess die Datenbankzeile geändert hat, die Sie über
updateRow()
aktualisieren? Gibt es eine Möglichkeit die Zeilen in derResultSet
zu sperren?
Lösung
Es ist wahrscheinlich ein ganzer Haufen von Technologien und Konzepten, die hier ins Spiel kommen, und die Dinge beginnen, ziemlich klebrig zu erhalten, wenn Sie Multi-Thread / Multi Anfrage Anwendungen unter Berücksichtigung starten.
Wie Iassevk erwähnt, sollten Sie in schauen Transaktionen rel="nofollow <
: - / a> die atomare Natur Ihres Updates, um sicherzustellen, ein sehr niedrige Ebene Beispiel etwas entlang der Linien von tun wäre,...
con.setAutoCommit(false);
try {
while (rs.next()) {
if (conditions_to_update) {
rs.updateString(...);
rs.updateRow();
}
}
con.setAutoCommit(true);
} catch (Exception ex) {
//log the exception and rollback
con.rollback();
} finally {
con.close();
}
Alle Updates würden dann in derselben Transaktion chargiert werden. Wenn eines des Updates eine Ausnahme (wie ein ungültiger Wert oder die Verbindung andernfalls teilweise durch die Ergebnisse) erzeugt, würde die ganze Menge mehr rückgängig gemacht werden. (Schließlich hinzugefügt, weil ich ein Champion davon bin; p)
Dies ist jedoch nicht Ihr zweites Problem beheben, die zwei sind konkurrierende Methoden versuchen, die gleiche Tabelle zu aktualisieren - eine Race-Bedingung. Es gibt in meinem Kopf, zwei Ansätze hier - jeder hat seine Vor- und Nachteile
.Der einfachste Ansatz wäre href="http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html" zum sperren - dies würde minimale Änderungen am Code erfordert aber einen ziemlich großen Nachteil hat. In der Annahme, dass, wie bei den meisten Anwendungen, es ist mehr lesen, dass der Schreib: die Tabellensperren verhindert, dass alle anderen Benutzer aus den Daten sehen, mit der Wahrscheinlichkeit wird der Code hängt, wartet, bis die Verriegelung zu lösen, bevor die Verbindung Time-out Tritte in und löst eine Ausnahme.
Je komplexer Ansatz besteht darin, sicherzustellen, dass die Verfahren zur Durchführung dieses Updates in einem Thread-sichere Art und Weise umgesetzt werden. Zu diesem Zweck:
- Alle Updates für diese Tabelle über eine einzige Klasse geben
- implementiert, die Klasse ein Muster Singleton, oder macht die Aktualisierungsmethoden als statische Methoden
- Die Update-Methoden verwenden, um das Synchronisierte Stichwort zu verhindern Rennbedingungen
Andere Tipps
Verwenden Transaktionen.
Was passiert, wenn ein anderer Prozess die Datenbankzeile geändert hat, die Sie über updateRow aktualisieren ()? Gibt es eine Möglichkeit die Zeilen im ResultSet zu sperren?
In Oracle können Sie irgendwie markieren bestimmte Zeilen für die Aktualisierung durch die folgende SQL-Ausgabe.
select cola, colB from tabA for update;
Die nächste Transaktion / Thread / app, die diese Zeile zu aktualisieren versucht, wird eine Ausnahme erhalten. sehen dies für weitere Details - http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4530093713805