Java JDBC Einführung
Was JDBC ist, wie es den Datenbankzugriff in Java abstrahiert und der Aufbau der JDBC API.
JDBC (Java Database Connectivity) ist die Standard-API für die Kommunikation mit einer relationalen Datenbank aus Java heraus. Sie befindet sich in den Paketen java.sql und javax.sql und bietet eine einheitliche, herstellerunabhängige Möglichkeit, eine Verbindung zu öffnen, SQL zu senden und Ergebnisse zu lesen — unabhängig davon, ob die Datenbank dahinter PostgreSQL, MySQL, Oracle, SQL Server oder eine eingebettete Engine wie H2 ist. Lerne die API einmal, und nur die Verbindungs-URL ändert sich beim Wechsel der Datenbank.
Die Grundidee: eine schlanke, einheitliche Schicht über viele Datenbanken
Der Code wird gegen Interfaces geschrieben — Connection, Statement, ResultSet. Die eigentlichen Klassen, die diese implementieren, werden in einem herstellerspezifischen Treiber-JAR geliefert. Die Aufgabe von JDBC ist es, deinen Code auf der Interface-Seite dieser Grenze zu halten, sodass ein Datenbankwechsel eine Konfigurationsänderung ist und kein Neuprogrammieren.
Die zentralen Typen
Eine Handvoll von Interfaces taucht in fast jedem JDBC-Programm auf:
| Interface | Rolle |
|---|---|
DriverManager | Findet einen Treiber für deine URL und gibt eine Connection zurück |
Connection | Eine aktive Sitzung mit der Datenbank; die Fabrik für Statements |
Statement | Sendet einen festen SQL-String |
PreparedStatement | Sendet eine parametrisierte SQL-Vorlage (die sichere Standardwahl) |
CallableStatement | Ruft eine gespeicherte Prozedur auf |
ResultSet | Ein Cursor über die von einer Abfrage zurückgegebenen Zeilen |
SQLException | Die geprüfte Ausnahme, die jeder JDBC-Aufruf werfen kann |
Die Struktur eines jeden JDBC-Programms
Fast jeder Datenzugriff folgt denselben fünf Schritten. Hier ist ein Beispiel gegen eine Live-Datenbank, mit try-with-resources, sodass jede Ressource sich selbst schließt:
String url = "jdbc:postgresql://localhost:5432/shop";
String sql = "SELECT id, name FROM product WHERE price < ?";
try (Connection conn = DriverManager.getConnection(url, "app", "secret");
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setBigDecimal(1, new BigDecimal("9.99"));
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " " + rs.getString("name"));
}
}
}Das heißt: (1) eine Datenbank mit einer URL benennen, (2) eine Connection öffnen, (3) ein Statement erstellen, (4) es ausführen, (5) das ResultSet lesen — dann alles in umgekehrter Reihenfolge schließen. Der Rest dieses Teils erläutert jeden Schritt im Detail.
Ein herstellerunabhängiges Typsystem
SQL-Spalten sind keine Java-Typen. JDBC überbrückt die beiden mit den java.sql.Types-Konstanten — VARCHAR, INTEGER, TIMESTAMP und so weiter — und einem parallelen Satz von getXxx/setXxx-Methoden. Diese Zuordnung verursacht selten Probleme, aber sie ist der Grund, warum eine DATE-Spalte zu java.sql.Date und ein NUMERIC zu BigDecimal konvertiert wird.
Ein ausgearbeitetes Beispiel: der Einstiegspunkt ohne installierten Treiber
Dieses Programm stellt keine Verbindung zu irgendetwas her — es untersucht die JDBC-Maschinerie selbst. Es fragt den DriverManager, welche Treiber registriert sind, zeigt den genauen Vertrag, den man erhält, wenn keiner einer URL entspricht, und gibt einige der Typkonstanten aus, auf denen die API aufgebaut ist.
Was aus dem Programmablauf zu entnehmen ist:
getConnectionist der einzige Einstiegspunkt und wird durch denDriverManagervermittelt. Du erstellst eine Verbindung nie mitnew— du benennst eine Datenbank mit einer URL und JDBC leitet die Anfrage weiter. Die Laufzeitumgebung hat hier keinen registrierten Treiber, daher ist die Anzahl0.- Wenn kein Treiber die URL beansprucht, gibt JDBC nicht
nullzurück und hängt sich nicht auf — es wirft eineSQLExceptionmit der Meldung 'No suitable driver found'. Jede JDBC-Methode signalisiert auf diese Weise einen Fehler, weshalbSQLExceptiongeprüft ist und du sie überall behandelst. - Die Ausnahme trägt einen SQLState (
08001, die standardmäßige Klasse 'client unable to establish connection'). SQLState-Codes sind über Hersteller hinweg portierbar, im Gegensatz zu den ganzzahligen Fehlercodes, die herstellerspezifisch sind. - Die
java.sql.Types-Konstanten sind einfacheint-Werte (VARCHARist 12,INTEGERist 4). So benennt die API SQL-Typen unabhängig von einer bestimmten Datenbank, und du wirst sie in späteren Kapiteln ansetNullundregisterOutParameterübergeben. - Hier war keine Datenbank erforderlich. Die JDBC-API ist Teil des JDK; nur der Treiber ist extern. Diese Trennung ist das gesamte Design — dein Code kompiliert und arbeitet mit
java.sql-Typen, ohne dass eine Datenbank in Sicht ist.
Wann JDBC einzusetzen ist
JDBC ist das Fundament, auf dem jedes höherstufige Java-Datenwerkzeug aufbaut. Object-Relational-Mapper wie Hibernate oder JPA, Query-Builder wie jOOQ und leichtgewichtigere Helfer wie Springs JdbcTemplate rufen alle intern JDBC auf. Greife direkt auf rohe JDBC zurück, wenn du volle Kontrolle über das SQL willst, einen minimalen Abhängigkeits-Footprint benötigst oder lernen möchtest, wie die Schicht tatsächlich funktioniert. Greife auf einen ORM zurück, wenn du Zeilen lieber auf Objekte abbilden und den Boilerplate überspringen möchtest. In jedem Fall sind die Konzepte in diesem Teil — Verbindungen, Statements, Result Sets und Transaktionen — das, was diese Werkzeuge für dich verwalten.
Was der Rest dieses Teils behandelt
Treiber laden und auswählen, eine Connection öffnen und konfigurieren, die drei Statement-Arten (Statement, PreparedStatement und CallableStatement) sowie die Navigation in einem ResultSet, dazu Transaktionen, Batch-Updates und das Lesen von Datenbank-Metadaten. Das nächste Kapitel beginnt dort, wo jede Verbindung beginnt: beim Treiber.