In der Klausur muesst ihr JDBC-Code nicht nur lesen und kommentieren, sondern auch selbst SCHREIBEN und AENDERN. Bonusaufgaben: Syntaxfehler korrigieren, Java-Programme umschreiben. Ueber die Muster unten sollen tippfertig sitzen.
Zusammenfassung
JDBC (Java Database Connectivity) ist die Java-API fuer den standardisierten Zugriff auf relationale Datenbanken via DBMS-spezifische Treiber (typisch Typ 4, pure Java). Kernelemente sind DriverManager, Connection, PreparedStatement und ResultSet - kombiniert mit expliziter Transaktionssteuerung ueber setAutoCommit/commit/rollback und automatischer Ressourcenfreigabe per try-with-resources. Der wichtigste Praxis-Reflex: immer PreparedStatement mit ?-Platzhaltern statt Statement mit String-Konkatenation verwenden, um SQL Injection zu verhindern.
Kernkonzepte
Class.forName und DriverManager
Class.forName(org.postgresql.Driver) laedt die Treiberklasse und registriert sie beim DriverManager. Danach liefert DriverManager.getConnection(url, user, pw) eine Connection. Die URL hat die Form jdbc:<dbms>://host:port/db. Seit JDBC 4 werden Treiber via ServiceLoader oft automatisch geladen - Class.forName wird aber in Lehrbeispielen weiter gezeigt.
Treiber laden, dann Verbindung holen - erst Class.forName, dann DriverManager.getConnection.
Connection
Repraesentiert die aktive Verbindung zur Datenbank. Ueber die Connection werden Statements erstellt und Transaktionen gesteuert (setAutoCommit, commit, rollback). Nach Gebrauch muss sie geschlossen werden - am besten via try-with-resources. Eine Connection kapselt einen Netzwerk-Socket zum DBMS.
Eine Verbindung, viele Statements - Connection ist teuer, Statements sind billig.
Statement vs PreparedStatement vs CallableStatement
Statement fuer statische SQL-Strings ohne Parameter (SQL Injection Gefahr bei Konkatenation, keine Wiederverwendung). PreparedStatement fuer parametrisierte Abfragen mit Platzhaltern ?, vorkompiliert, sicher gegen SQL Injection, ideal bei wiederholten Aufrufen. CallableStatement fuer Stored Procedure Calls mit Syntax {CALL name(?)}.
PreparedStatement fast immer, Statement fast nie - Injection-sicher und performant.
ResultSet
Datenkontainer / Cursor fuer SELECT-Ergebnisse. Startet VOR der ersten Zeile. rs.next() bewegt Cursor eine Zeile weiter und liefert boolean. Zugriff auf Werte via getInt(spalte), getString(spalte) - entweder per Spaltenname oder 1-basiertem Index. Standardmaessig Forward-Only und Read-Only.
Erst next, dann get - der Cursor steht anfangs vor der ersten Zeile.
Transaktionen mit setAutoCommit, commit, rollback
Standard: autoCommit=true (jedes Statement eigene Transaktion). Fuer atomare Multi-Statement-Operationen setAutoCommit(false) aufrufen. Bei Erfolg conn.commit(), bei Fehler conn.rollback() im catch-Block. Am Ende autoCommit wieder auf true zuruecksetzen. Ohne diese Steuerung sind zusammengehoerige Aenderungen NICHT atomar.
autoCommit aus, dann commit oder rollback - alles oder nichts.
Exception Handling mit SQLException
Fast alle JDBC-Methoden werfen SQLException (checked exception). Muss per try-catch behandelt oder deklariert werden. SQLException bietet getMessage, getSQLState (SQL-Standard-Codes) und getErrorCode (DBMS-spezifisch). Bei Transaktionen im catch-Block immer rollback aufrufen.
Jede JDBC-Zeile kann werfen - im catch immer an rollback denken.
Ressourcen schliessen mit try-with-resources
Connection, Statement, PreparedStatement und ResultSet implementieren AutoCloseable. try (Resource r = ...) ruft close automatisch auf - auch bei Exception, in umgekehrter Deklarationsreihenfolge. Loest das haeufige Problem vergessener close-Aufrufe (Ressourcen-Leak, Sperren, Deadlocks).
try-with-resources statt manuellem close in finally - Java 7 aufwaerts Standard.
PreparedStatement Parameter binden
Nach conn.prepareStatement(sql mit ?) werden Parameter mit setInt(index, wert), setString(index, wert), setDate, setBigDecimal etc. gebunden. Index ist 1-basiert (nicht 0-basiert). Erst danach executeQuery oder executeUpdate aufrufen. Reihenfolge der ? bestimmt den Index.
Index 1-basiert, Typ passend - setInt fuer INTEGER, setString fuer VARCHAR.
Wichtige Details
SQL Injection Schutz: NIE Benutzereingaben per String-Konkatenation in SQL einbauen. Immer PreparedStatement mit Platzhaltern ? und setXxx-Methoden verwenden. Beispiel Angriff: password = xxx' OR 1 = 1 umgeht Authentifizierung wenn per String-Konkatenation zusammengesetzt.
Statement vs PreparedStatement Performance: PreparedStatement wird einmal vom DBMS geparst und der Ausfuehrungsplan gecached. Bei wiederholter Ausfuehrung (nur setXxx neu, executeQuery neu) ist es deutlich schneller. Statement wird jedes Mal neu geparst.
Batch-Update mit addBatch() sammelt Statements und executeBatch() sendet sie in einem Netzwerk-Roundtrip an das DBMS. Reduziert Roundtrip-Overhead massiv bei vielen INSERTs/UPDATEs. Rueckgabe ist int[] mit betroffenen Zeilen pro Statement.
Ressourcen schliessen in korrekter Reihenfolge: ResultSet vor Statement vor Connection. try-with-resources macht das automatisch in umgekehrter Deklarationsreihenfolge - deshalb Connection zuerst deklarieren, dann Statement, dann ResultSet.
ResultSet Cursor-Typen: TYPE_FORWARD_ONLY (Standard, nur next()), TYPE_SCROLL_INSENSITIVE (auch previous, absolute, ohne Live-Updates), TYPE_SCROLL_SENSITIVE (mit Live-Updates). Concurrency: CONCUR_READ_ONLY oder CONCUR_UPDATABLE.
PreparedStatement Parameter sind 1-basiert! ps.setInt(1, wert) fuer das erste ?, ps.setString(2, wert) fuer das zweite ?. ps.setInt(0, wert) wirft SQLException.
JDBC verwendet nur indizierte Parameter (?), NICHT named parameters (:name). Named Parameters gibt es nur bei Erweiterungen wie Spring JdbcTemplate oder JPA.
Metadata via ResultSetMetaData: rsmd = rs.getMetaData(); rsmd.getColumnCount(); rsmd.getColumnName(i); - fuer generische Anzeige unbekannter Ergebnisstrukturen. DatabaseMetaData ueber conn.getMetaData() gibt Info ueber DBMS.
SQLException hat getMessage (lesbar), getSQLState (SQLSTATE-Code nach Standard) und getErrorCode (DBMS-spezifisch). Beim Debugging alle drei loggen. Chained Exceptions ueber getNextException.
Connection Pooling: In Produktion nie DriverManager.getConnection direkt - Verbindungsaufbau ist teuer. Stattdessen DataSource mit Connection Pool (HikariCP, c3p0) verwenden. Fuer Klausur meistens DriverManager gezeigt.
Der JDBC-Treiber muss zur Laufzeit im Classpath sein. Bei Maven: postgresql als dependency in pom.xml. Bei Kommandozeile: java -cp postgresql.jar:. MyProgram.
Boilerplate von JDBC ist der Hauptnachteil - viel wiederholter Code fuer Verbindung, Statement, Iteration, Fehlerbehandlung. Deshalb in Praxis oft ORM (Hibernate/JPA) oder Query-Builder (jOOQ). Fuer die Klausur muss man das Boilerplate aber koennen.
Code-Muster - Diese SOLLEN sitzen
Jedes Muster einmal mitschreiben. Der Kopieren-Button hilft beim Ueben in einer IDE.
1. Verbindung aufbauen und schliessen mit try-with-resources
Der absolute Standard-Einstieg jeder JDBC-Anwendung. Treiber wird geladen, Connection wird geoeffnet und garantiert wieder geschlossen - auch bei Exception. Das try-with-resources ruft close() automatisch auf, deshalb kein finally noetig.
2. SELECT mit PreparedStatement und ResultSet-Schleife
Ausfuehren einer Anfrage mit Benutzereingabe. Der Fragezeichen-Platzhalter und setString/setInt verhindern SQL Injection. Das ResultSet wird mit rs.next() Zeile fuer Zeile abgearbeitet.
String sql = "SELECT matrnr, name, semester FROM studenten WHERE semester >= ?";
try (Connection conn = DriverManager.getConnection(url, user, pw);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, 3);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int matrnr = rs.getInt("matrnr");
String name = rs.getString("name");
int sem = rs.getInt("semester");
System.out.println(matrnr + " " + name + " " + sem);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
Kern-Zeilen zum Auswendiglernen:
conn.prepareStatement(sql) mit Platzhaltern
ps.setInt(1, wert) - Parameter binden, 1-basiert
ResultSet rs = ps.executeQuery()
while (rs.next()) { rs.getString(spalte); }
3. INSERT / UPDATE / DELETE mit PreparedStatement
Datenaenderungen werden mit executeUpdate ausgefuehrt (nicht executeQuery). Der Rueckgabewert ist die Anzahl betroffener Zeilen als int. Auch hier PreparedStatement mit setXxx-Methoden verwenden.
executeUpdate() statt executeQuery() bei INSERT/UPDATE/DELETE
Rueckgabewert int = Anzahl betroffener Zeilen
ps.setInt / ps.setString mit 1-basiertem Index
PreparedStatement wiederverwendbar durch setXxx neu setzen
4. Transaktion mit setAutoCommit, commit und rollback
Zwei zusammengehoerige Aenderungen (klassisch: Ueberweisung zwischen zwei Konten) muessen atomar erfolgen. Ohne setAutoCommit(false) wird jedes Statement einzeln committet - das darf hier nicht passieren.
conn.commit() - am Ende des try-Blocks nach allen Statements
conn.rollback() - im catch bei jedem Fehler
finally: setAutoCommit(true) und close()
5. Batch-Update fuer viele Datensaetze
1000 einzelne INSERTs = 1000 Netzwerk-Roundtrips = langsam. Batch fasst mehrere Statements zusammen und sendet sie als Block. Idealerweise kombiniert mit einer Transaktion.
String sql = "INSERT INTO logeintraege (zeitstempel, nachricht) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, pw)) {
conn.setAutoCommit(false);
try (PreparedStatement ps = conn.prepareStatement(sql)) {
for (int i = 0; i < 1000; i++) {
ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
ps.setString(2, "Nachricht Nr " + i);
ps.addBatch();
if (i % 100 == 0) {
ps.executeBatch();
}
}
int[] ergebnisse = ps.executeBatch();
conn.commit();
System.out.println("Insgesamt " + ergebnisse.length + " Statements");
} catch (SQLException e) {
conn.rollback();
throw e;
}
}
Kern-Zeilen zum Auswendiglernen:
ps.addBatch() - Statement zur Batch hinzufuegen
ps.executeBatch() - alle gesammelten Statements ausfuehren
conn.setAutoCommit(false) - Batch in einer Transaktion
Rueckgabe int[] = Anzahl betroffener Zeilen pro Statement
6. Fehlerhaftes Snippet erkennen und korrigieren
Klassische Klausur-Aufgabe. Das erste Snippet enthaelt mehrere Anti-Patterns: Statement (kein PreparedStatement) mit String-Konkatenation (SQL Injection), kein close (Ressourcen-Leak), autoCommit nicht gesetzt bei zwei zusammengehoerigen Statements, kein Rollback im Fehlerfall.
// FEHLERHAFT:
Connection conn = DriverManager.getConnection(url, user, pw);
Statement stmt = conn.createStatement();
String userInput = request.getParameter("name");
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE name = '" + userInput + "'");
stmt.executeUpdate("UPDATE konto SET saldo = saldo - 100 WHERE id = 1");
stmt.executeUpdate("UPDATE konto SET saldo = saldo + 100 WHERE id = 2");
// KORRIGIERT:
String sel = "SELECT * FROM users WHERE name = ?";
String upd1 = "UPDATE konto SET saldo = saldo - ? WHERE id = ?";
String upd2 = "UPDATE konto SET saldo = saldo + ? WHERE id = ?";
try (Connection conn = DriverManager.getConnection(url, user, pw)) {
conn.setAutoCommit(false);
try (PreparedStatement ps = conn.prepareStatement(sel)) {
ps.setString(1, userInput);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { /* ... */ }
}
}
try (PreparedStatement p1 = conn.prepareStatement(upd1);
PreparedStatement p2 = conn.prepareStatement(upd2)) {
p1.setInt(1, 100); p1.setInt(2, 1); p1.executeUpdate();
p2.setInt(1, 100); p2.setInt(2, 2); p2.executeUpdate();
conn.commit();
} catch (SQLException e) {
conn.rollback();
throw e;
}
}
Kern-Zeilen zum Auswendiglernen:
Statement + String-Konkatenation ist SQL Injection anfaellig
PreparedStatement mit ? und setXxx ist sicher
Fehlendes close() = Ressourcen-Leak - try-with-resources loest das
Zwei zusammengehoerige Updates brauchen setAutoCommit(false) + commit/rollback
7. Stored Procedure per CallableStatement aufrufen
Zum Aufruf einer gespeicherten Prozedur in der Datenbank nutzt man CallableStatement mit prepareCall und der Syntax {CALL name(?, ?)}. Parameter werden wie bei PreparedStatement gebunden.
conn.prepareCall({CALL name(?)}) mit geschweiften Klammern
setInt / setString wie sonst auch
executeQuery() bzw executeUpdate() je nach Prozedur
Beispiele
Vollstaendiger JDBC-Ablauf fuer SELECT
Klassisches 5-Schritt-Muster: Treiber laden, Verbindung aufbauen, PreparedStatement erstellen mit Platzhaltern, Parameter binden, executeQuery aufrufen, ResultSet in while-Schleife durchlaufen und mit rs.next() Zeile fuer Zeile abarbeiten, Ressourcen im richtigen umgekehrten Reihenfolge schliessen (rs, ps, conn) - am besten via try-with-resources damit dies automatisch geschieht.
1. Class.forName(org.postgresql.Driver) - Treiber registrieren
2. DriverManager.getConnection(url, user, pw) - Verbindung
3. conn.prepareStatement(SELECT ... WHERE x = ?) - PreparedStatement
4. ps.setInt(1, wert) - Parameter binden
5. ResultSet rs = ps.executeQuery() - Ausfuehren
6. while (rs.next()) { rs.getString(name); rs.getInt(alter); } - Iterieren
7. Ressourcen schliessen (automatisch mit try-with-resources)
Banktransaktion mit Rollback
Klassische Uni-Aufgabe: Betrag von Konto A abbuchen und auf Konto B gutschreiben. Beide UPDATEs muessen zusammen erfolgreich sein oder gar nicht. autoCommit muss auf false gesetzt werden, damit die zwei Statements in einer Transaktion gebuendelt werden. Bei Exception: rollback im catch-Block. Bei Erfolg: commit am Ende des try-Blocks. Im finally: autoCommit wieder auf true setzen und Connection schliessen.
conn.setAutoCommit(false)
UPDATE konto SET saldo = saldo - 100 WHERE id = A
UPDATE konto SET saldo = saldo + 100 WHERE id = B
conn.commit()
catch (SQLException e) { conn.rollback(); }
Fehleranalyse eines schlechten Snippets
Ein typisches Klausur-Beispiel: Statement (kein PreparedStatement) mit String-Konkatenation, kein close, kein try-catch, autoCommit nicht gesetzt. Studenten muessen die drei bis vier Fehler benennen (SQL Injection Risiko, Ressourcen-Leak, keine Transaktion, kein Exception-Handling) und den Code korrigieren.
Fehlerhafter Code: stmt.executeQuery(SELECT * FROM users WHERE name = + userInput)
Korrekt: PreparedStatement mit ? und ps.setString(1, userInput) in try-with-resources
Batch-Update fuer 1000 Datensaetze
Grosse Datenmengen mit einzelnen executeUpdate-Aufrufen verursachen viele Roundtrips. Loesung: PreparedStatement einmal vorbereiten, in Schleife addBatch aufrufen und am Ende executeBatch. Zusaetzlich autoCommit=false verwenden damit alle 1000 Inserts in einer Transaktion laufen. Am Ende commit.
JDBC-Ablauf im Ueberblick
Haeufige Fragen
Warum PreparedStatement statt Statement?
Drei Gruende: 1) Schutz vor SQL Injection durch getrennte Uebergabe von SQL-Struktur und Parametern, 2) Performance durch Vorkompilierung und Wiederverwendung des Query-Plans bei wiederholtem Aufruf, 3) Typsicherheit durch setInt, setString, setDate statt String-Konkatenation.
Was macht Class.forName und ist es noch noetig?
Class.forName laedt die Treiber-Klasse und registriert sie beim DriverManager. Seit JDBC 4 (Java 6) ist der Aufruf oft nicht mehr noetig, da moderne Treiber via ServiceLoader automatisch geladen werden. In Klausuraufgaben wird die explizite Registrierung aber meist noch gezeigt und gefordert.
Wie unterbindet man SQL Injection zuverlaessig?
Immer PreparedStatement mit Platzhaltern ? verwenden und Parameter via setInt, setString etc. binden. NIE Benutzereingaben per String-Konkatenation in den SQL-String einfuegen. Alternativ Stored Procedures oder ein Persistenz-Framework (JPA/Hibernate) verwenden.
Was passiert wenn man autoCommit=true laesst und mitten in einer Transaktion einen Fehler bekommt?
Bei autoCommit=true wird jedes einzelne Statement sofort committet. Das erste UPDATE (Abbuchung) waere also schon persistiert wenn das zweite (Gutschrift) fehlschlaegt - die Datenbank ist inkonsistent. Deshalb setAutoCommit(false) verwenden und explizit commit oder rollback aufrufen.
Warum try-with-resources statt manuellem close in finally?
try-with-resources ruft close() automatisch in umgekehrter Reihenfolge der Deklaration auf - auch bei Exceptions. Das eliminiert Boilerplate-Code, verhindert vergessene close-Aufrufe (Ressourcen-Leak) und ist die empfohlene Java-Praxis seit Java 7. Alle JDBC-Objekte (Connection, Statement, ResultSet) implementieren AutoCloseable.
Was ist der Unterschied zwischen executeQuery, executeUpdate und execute?
executeQuery: fuer SELECT, gibt ResultSet zurueck. executeUpdate: fuer INSERT/UPDATE/DELETE/DDL, gibt int (Anzahl betroffener Zeilen) zurueck. execute: universell, gibt boolean zurueck (true wenn ResultSet vorhanden), danach getResultSet oder getUpdateCount aufrufen. Fuer Klausur: executeQuery nur bei SELECT.
Was macht ResultSet.next() genau?
next() bewegt den Cursor eine Zeile weiter und gibt true zurueck wenn eine weitere Zeile existiert, false sonst. Vor dem ersten Aufruf steht der Cursor VOR der ersten Zeile - man muss also immer erst next() aufrufen bevor man mit getInt/getString zugreift. Deshalb das Muster while (rs.next()) { ... }.
Was ist der Unterschied zwischen JDBC Typ 2 und Typ 4 Treiber?
Typ 2 (Native API): JDBC ruft eine DBMS-spezifische native C-Library auf, die clientseitig installiert sein muss. Typ 4 (Java-nativ, pure Java): Treiber ist komplett in Java geschrieben und kommuniziert direkt ueber das Netzwerkprotokoll der Datenbank. Typ 4 ist heute Standard (portabel, keine native Installation noetig).
Pruefungsfragen
Fortschritt
0 / 14
Frage 1kurzantwort
Welcher JDBC-Aufruf laedt die Treiberklasse fuer PostgreSQL?
Antwort:
Class.forName("org.postgresql.Driver");
Der voll qualifizierte Klassenname des JDBC-Treibers wird an Class.forName uebergeben. Dies laedt und registriert den Treiber beim DriverManager.
Frage 2multiple-choice
Welches Interface schuetzt vor SQL Injection?
Frage 3wahr-falsch
Wahr oder falsch: rs.next() muss vor dem ersten Zugriff auf ResultSet-Werte aufgerufen werden.
Frage 4code-schreiben
Ergaenze das PreparedStatement: Schreibe Java-Code der alle Studenten mit Semester groesser als einem Parameter selectiert und ausgibt.
Wichtige Elemente: try-with-resources fuer Connection und PreparedStatement, ? Platzhalter, setInt mit 1-basiertem Index, ResultSet ebenfalls in try-with-resources, while(rs.next()) fuer Iteration.
Frage 5kurzantwort
Was ist der Unterschied zwischen executeQuery und executeUpdate?
Beide sind Methoden auf Statement/PreparedStatement. Die Wahl haengt davon ab ob ein Ergebnis (Menge von Zeilen) erwartet wird oder nur die Anzahl geaenderter Zeilen.
Frage 6code-schreiben
Schreibe eine Banktransaktion die 50 Euro von Konto 1 auf Konto 2 ueberweist mit korrektem Rollback im Fehlerfall.
Musterloesung:
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, pw);
conn.setAutoCommit(false);
try (PreparedStatement ps1 = conn.prepareStatement("UPDATE konto SET saldo = saldo - ? WHERE id = ?");
PreparedStatement ps2 = conn.prepareStatement("UPDATE konto SET saldo = saldo + ? WHERE id = ?")) {
ps1.setBigDecimal(1, new BigDecimal("50")); ps1.setInt(2, 1); ps1.executeUpdate();
ps2.setBigDecimal(1, new BigDecimal("50")); ps2.setInt(2, 2); ps2.executeUpdate();
conn.commit();
}
} catch (SQLException e) {
if (conn != null) try { conn.rollback(); } catch (SQLException ex) {}
throw new RuntimeException(e);
} finally {
if (conn != null) try { conn.close(); } catch (SQLException e) {}
}
Kernpunkte: setAutoCommit(false), beide Updates im try-Block, commit am Ende, rollback im catch, close im finally.
Frage 7multiple-choice
Welche der folgenden Aussagen zu try-with-resources sind korrekt?
Frage 8erkennen
Erkenne die Fehler im Code: Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE name = '" + name + "'");
Antwort:
1) Statement statt PreparedStatement - SQL Injection Gefahr durch String-Konkatenation. 2) Fehlendes close - Ressourcen-Leak. 3) Kein try-catch fuer SQLException.
Korrekt waere: PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?"); ps.setString(1, name); - alles in try-with-resources.
Frage 9wahr-falsch
Wahr oder falsch: setAutoCommit(false) ist per Default gesetzt.
Frage 10multiple-choice
Wozu dient conn.rollback()?
Frage 11code-schreiben
Schreibe einen Batch-Update der 5 Log-Eintraege einfuegt.
addBatch() sammelt die Statements, executeBatch() sendet sie zusammen. Kombination mit setAutoCommit(false) und commit fasst alles in eine Transaktion.
Frage 12kurzantwort
Warum ist der 1-basierte Index bei setInt/setString eine haeufige Fehlerquelle?
Antwort:
Weil Java Arrays und Collections 0-basiert sind, PreparedStatement-Parameter aber ab 1 gezaehlt werden. Vertauschung fuehrt zu SQLException oder falschen Wertzuordnungen.
ps.setInt(0, x) wirft SQLException. Immer beim ersten ? mit 1 anfangen.
Frage 13wahr-falsch
Wahr oder falsch: Ein ResultSet kann nach dem Schliessen der Connection noch verwendet werden.
Frage 14kurzantwort
Nenne drei Vorteile von PreparedStatement gegenueber Statement.
Antwort:
1) Schutz vor SQL Injection durch getrennte Uebergabe von Struktur und Parametern. 2) Performance durch Vorkompilierung und Wiederverwendung des Query-Plans. 3) Typsicherheit durch setInt, setString etc. statt fehleranfaelliger String-Konkatenation.
Zusaetzlich: bessere Lesbarkeit, einfacheres Escaping von Sonderzeichen, direkte Unterstuetzung fuer Datentypen wie Date und BigDecimal.