16.7 Elemente einer Datenbank hinzufügen und aktualisieren
Bisher haben wir executeQuery() benutzt, um Abfragen zu verfassen. Es lassen sich jedoch auch Einfüge-Operationen vornehmen, denn Tabelleninhalte bleiben nicht unveränderlich.
Das SQL-Kommando INSERT fügt Daten ein, und UPDATE aktualisiert sie. Damit Spalten verändert werden können, müssen wir in zwei Schritten vorgehen:
- eine SQL-Anweisung mit einem UPDATE aufbauen und
- anschließend executeUpdate() aufrufen.
Damit wird die Änderung wirksam. Dies ist eine andere Statement-Methode, bisher kannten wir nur executeQuery(). Neben den Methodennamen gibt es aber noch einen anderen Unterschied: executeUpdate() liefert als Rückgabewert ein int, das angibt, wie viele Zeilen von der Änderung betroffen sind.
Beispiel |
Folgende SQL-Anweisung ändert die Adresse eines Lieferanten einer fiktiven Relation: String updateString = "UPDATE Lieferanten SET Adresse = " + |
Die Methode gibt uns immer zurück, wie viele Zeilen von den Änderungen betroffen sind. Sie ist 0, falls das SQL-Statement nichts bewirkt.
interface java.sql.Statement |
- int executeUpdate(String sql) throws SQLException
Führt eine SQL-Anweisung aus, die Manipulationen an der Datenbank vornimmt. Die SQL-Anweisungen sind in der Regel INSERT-, UPDATE- oder DELETE-Anweisungen. Zurückgegeben wird die Anzahl der veränderten Zeilen, oder null, falls eine SQL-Anweisung nichts verändert hat.
16.7.1 Batch-Updates
Das Einfügen und Ändern großer Mengen von Daten kostet viel Zeit, da für jede Modifikation ein INSERT oder UPDATE über ein Statement-Objekt abgewickelt werden muss. Eine Verbesserung stellen Batch-Updates dar, die in einem Rutsch gleich eine ganze Reihe von Daten zur Datenbank transferieren. Statt mit execute() und deren Varianten zu arbeiten, nutzen wir die Methode executeBatch(). Damit zuvor die einzelnen Aktionen dem Statement-Objekt mitgeteilt werden können, bietet die Klasse die Methoden addBatch() und clearBatch() an. Die Datenbank führt die Anweisungen in der Reihenfolge aus, wie sie im Batch-Prozess eingefügt wurden. Ein Fehler wird über eine BatchUpdateException angezeigt.
Beispiel |
Wir fügen einige Einträge der Datenbank als Batch hinzu. con sei unser Connection-Objekt: int[] updateCounts = null; |
Nach dem Abarbeiten von executeBatch() erhalten wir als Rückgabewert ein int-Feld mit den Ergebnissen der Ausführung. Dies liegt daran, dass in der Batch-Verarbeitung ganz unterschiedliche Anweisungen vorgenommen werden können und jede davon einen unterschiedlichen Rückgabewert verwendet.
Soll der gesamte Ablauf als Transaktion gewürdigt werden, so setzen wir im try-Block den AutoCommit-Modus auf false, damit nicht jede SQL-Anweisung als einzelne Transaktion gewertet wird. Im Fall eines Fehlers müssen wir im catch-Block ein Rollback ausführen. Übertragen wir dies auf das obere Beispiel, dann müssen nur die beiden Anweisungen für die Transaktion eingesetzt werden:
try
{
con.setAutoCommit( false );
Statement s .....
...
}
catch ( BatchUpdateException e )
{
con.rollback();
}
16.7.2 Die Ausnahmen bei JDBC, SQLException und Unterklassen
Normale Ausnahmen in Java tragen lediglich eine Nachricht, die sich mit getMessage() erfragen lässt. Da bei Datenbanken aber viele Dinge schiefgehen können, hätten die Architekten der JDBC-API viel zu tun, wenn sie für jede mögliche Ausnahme eine Exception-Klasse bereitstellen wollten. Doch wegen der schier unüberschaubaren Anzahl an Fehlern haben sie sich für ein anderes Modell entschieden.
JDBC-Fehlerbasisklasse SQLException
Zunächst einmal gibt es für JDBC-Ausnahmen den Basistyp SQLException. Zusätzlich speichert jedes SQLException-Objekt Fehlercodes, die der JDBC-Treiber der Datenbank setzen und so über den konkreten Fehler informieren kann.
Die genauen Informationen einer SQL-Ausnahme sind über drei Methoden zugänglich:
- String getMessage(): eine textuelle Beschreibung des Fehlers
- String getSQLState(): Einen String mit dem SQL-Status. Hier gibt es zwei Konventionen. Einmal kann es ein SQL-Status nach der SQL-CLI-Spezifikation der Open Group (vor über zehn Jahren hieß sie X/Open) sein – oder ein SQL:2003-Code. Beide sind datenbankunabhängig. Nach welcher Spezifikation der Code formuliert ist, sagt die Methode getSQLStateType() vom DatabaseMetaData-Objekt. Der Open-Group-Standard ist üblich.
- int getErrorCode(): Ein Fehler-Code vom JDBC-Treiber. Er kommt vom Hersteller der Datenbank bzw. vom Datenbanktreiber. Er ist datenbankabhängig.
Der Open-Group-SQL-Status ist eigentlich eine Zahl, aber als String verpackt. Im Optimalfall ist der Code »00000«, was »Alles paletti« heißt. Die ersten beiden Ziffern stehen für die Fehlerklasse. 01 ist eine Warnung, 02 sagt, dass Daten fehlen, usw.[101](Unter ftp://ftp.software.ibm.com/ps/products/db2/info/vr6/htm/db2m0/db2state.htm bekommen Leser einen Überblick.)
Eine Verkettung unglücklicher Tatsachen
Eine SQLException hat eine Besonderheit, die sonst keine Ausnahme in der Java-Bibliothek aufweist. Sie implementiert die Schnittstelle Iterable<Throwable>:
class java.sql.SQLException |
Das heißt, dass eine SQLException ein Bündel von Ausnahmen repräsentieren kann und nicht nur genau eine. Welche JDBC-Ausnahmen noch an der SQLException hängen, liefert getNextException() bzw. steckt im Iterator der SQLException.
Beispiel |
Laufe alle Fehler ab: try { ... } |
SQLWarning
Nicht jeder Fehler bzw. jede Meldung der Datenbank ist gleich ein kritischer Fehler, der zum Abbruch der Datenbankoperationen führt. Die JDBC-API bietet mit der Klasse SQLWarning eine besondere Unterklasse von SQLException, doch wird sie nicht als Exception ausgelöst, sondern muss im Programm explizit über getWarnings() geholt werden. Die Typen Connection, ResultSet und Statement deklarieren diese Operation. Im besten Fall holen sich Entwickler alle Warnungen und loggen sie.
Da die SQLWarning eine SQLException ist, ist auch die Verarbeitung von SQL-Code und Fehlercode gleich. Anstatt jedoch mit getNextException() zu arbeiten, bietet SQLWarning die Methode getNextWarning() um zur nächsten Warnung vorzustoßen. Werden die Meldungen nicht geholt, dann werden sie bei der Ausführung der nächsten SQL-Anweisung gelöscht.
Daten fehlen
Für den SQL-Status »01004« und »22001« gibt es eine eigene Fehlerklasse, die DataTruncation. Sie ist ein spezieller Typ einer SQL-Warnung und wird immer dann erzeugt, wenn Daten während der Schreib- oder Leseoperationen verloren gingen. Die Meldung wird genauso geholt wie SQLWarning, nur wird mittels instanceof DataTruncation überprüft, ob es sich um DataTruncation handelt. Dies erfordert eine Typumwandlung von SQLWarning auf DataTruncation. Dann stehen Methoden wie getIndex() oder getTransferedSize() bereit, die aussagen, für welche Spalte wie viel Bytes korrekt übertragen wurden. DataTruncation ist die einzige Unterklasse von SQLWarning.
Abbildung 16.17: Vererbungshierarchie der JDBC-Fehlerklassen
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.