18.10.2 | Stapelaktualisierung |
Durch die Verwendung der Stapelaktualisierung können drastische Performance-Steigerungen erzielt werden. Bei einer Stapelaktualisierung werden SQL-Anweisungen nicht einzeln an den Datenbankserver geschickt. Sie werden zunächst auf Client-Seite gesammelt und anschließend gebündelt zur Ausführung an das Datenbanksystem übergeben. Dadurch wird der Kommunikationsaufwand zwischen JDBC-Treiber und Datenbanksystem deutlich reduziert. Das Prinzip wird in Abbildung 18.23 verdeutlicht.Große Vorteile bringen Stapelaktualisierungen immer dann, wenn viele SQL-Anweisungen nacheinander ausgeführt werden. Das ist z. B. der Fall, wenn ein Shop eine neue Lieferung bekommt und der momentane Bestand aktualisiert werden muss. Es werden viele gleichartige INSERT-Anweisungen erzeugt, die durch die Ausführung in Stapeln stark beschleunigt werden können.
Stapelaktualisierungen werden über dieselben Statement-Objekte ausgeführt wie die bisher vorgestellten SQL-Anweisungen auch. Stapelaktualisierungen unterstützen nur die Ausführung von INSERT, UPDATE und DELETE-Anweisungen. Bei der Ausführung von SQL-Anweisungen, die Ergebnismengen zurückliefern, wird eine SQLException ausgelöst.
Folgendes Beispiel zeigt, wie die Stapelaktualisierung durchgeführt wird:import java.sql.*; ... Connection con; int[] lager = null, titel = null; // Aufbauen der Verbindung und Initialisierung der // Arrays mit Titelnr und gelieferter Anzahl ... // Initialisierung der SQL_Verbindung String sql = "UPDATE titel SET lager = lager + ? WHERE tit_id = ?"; PreparedStatement prep = con.prepareStatement(sql); for(int i=0; i < lager.length; i++) { prep.setInt(1, lager[i]); prep.setLong(2, titel[i]); // Hinzufügen der Anweisung zum Stapel // Beim ersten Aufruf wird das Statement-Objekt // in den Stapel-Modus versetzt prep.addBatch(); } // Ausführen des Stapels int[] ergebnis = prep.executeBatch(); System.out.println(prep.getUpdateCount()+" Zeilen aktualisiert."); prep.close();Statement-Objekte werden in den Stapel-Modus versetzt, indem man dem Stapel explizit SQL-Anweisungen über die Methode addBatch() hinzufügt. Bei PreparedStatement und CallableStatement müssen hierzu zunächst alle Parameter mit Werten belegt werden. Bei einfachen Statement-Exemplaren wird addBatch() zusätzlich der auszuführende SQL-String übergeben. Befindet sich ein Statement-Objekt im Stapel-Modus, kann es erst dann wieder zur Ausführung von herkömmlichen SQL-Anweisungen benutzt werden, nachdem der Stapel mit executeBatch() abgeschickt oder mit clearBatch() gelöscht wurde.
executeBatch() liefert ein int-Array, das für jede ausgeführte Anweisung genau ein Element enthält. Bei Statement- und CallableStatement-Exemplaren enthält das Array jeweils die Anzahl der in der Datenbank aktualisierten Zeilen. Bei PreparedStatement wird der Wert -2 eingetragen, wenn die Ausführung geglückt ist. Die Gesamtzahl der aktualisierten Zeilen kann über die Methode getUpdateCount() ermittelt werden.
Werden Transaktionen mit commit() bestätigt, bleiben SQL-Anweisungen, die sich in noch nicht ausgeführten Stapeln befinden, auch weiterhin unausgeführt im Stapel verfügbar. Das heißt erst wenn der Stapel ausgeführt wurde, können die darin definierten Änderungen auch mit commit() bestätigt werden.
Bei der Durchführung von Stapelaktualisierungen sollte man generell folgende Punkte berücksichtigen:
- Dadurch, dass Änderungen zunächst auf Client-Seite gesammelt werden, wird die Ausführung der einzelnen SQL-Anweisungen verzögert. Werden in Statement-Objekten Daten abgefragt, die in noch nicht ausgeführten Stapeln verändert werden, kann das Abfrageergebnis die Änderungen noch nicht enthalten.
- Ausführungsfehler zu einzelnen SQL-Anweisungen werden erst zurückgegeben, nachdem der Stapel ausgeführt wurde. Sie müssen daher für alle SQL-Anweisungen im Stapel gemeinsam verarbeitet werden.
- Damit man bei Ausführungsfehlern in Stapelaktualisierungen alle Anweisungen wieder rückgängig machen kann, sollte man vor der Ausführung des Stapels Auto-Commit deaktivieren.