W3docs

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:

InterfaceRolle
DriverManagerFindet einen Treiber für deine URL und gibt eine Connection zurück
ConnectionEine aktive Sitzung mit der Datenbank; die Fabrik für Statements
StatementSendet einen festen SQL-String
PreparedStatementSendet eine parametrisierte SQL-Vorlage (die sichere Standardwahl)
CallableStatementRuft eine gespeicherte Prozedur auf
ResultSetEin Cursor über die von einer Abfrage zurückgegebenen Zeilen
SQLExceptionDie 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.

java— editable, runs on the server

Was aus dem Programmablauf zu entnehmen ist:

  • getConnection ist der einzige Einstiegspunkt und wird durch den DriverManager vermittelt. Du erstellst eine Verbindung nie mit new — du benennst eine Datenbank mit einer URL und JDBC leitet die Anfrage weiter. Die Laufzeitumgebung hat hier keinen registrierten Treiber, daher ist die Anzahl 0.
  • Wenn kein Treiber die URL beansprucht, gibt JDBC nicht null zurück und hängt sich nicht auf — es wirft eine SQLException mit der Meldung 'No suitable driver found'. Jede JDBC-Methode signalisiert auf diese Weise einen Fehler, weshalb SQLException geprü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 einfache int-Werte (VARCHAR ist 12, INTEGER ist 4). So benennt die API SQL-Typen unabhängig von einer bestimmten Datenbank, und du wirst sie in späteren Kapiteln an setNull und registerOutParameter ü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.

Übungen

Übung
Warum wird in einem typischen JDBC-Programm der Anwendungscode gegen Interfaces wie Connection und ResultSet geschrieben und nicht gegen konkrete Klassen?
Warum wird in einem typischen JDBC-Programm der Anwendungscode gegen Interfaces wie Connection und ResultSet geschrieben und nicht gegen konkrete Klassen?
Was this page helpful?