Java Anwendungsentwicklung – Tag 6 von 10
Von Franz-Martin, CTO bei Java Fleet Systems Consulting
Schwierigkeit: 🟢 Grundlagen
Dauer: ~6-8 Stunden
Voraussetzungen: Tag 1-5 abgeschlossen (GUI-Teil)
🗺️ Deine Position im Kurs
| Tag | Thema | Niveau | Status |
|---|---|---|---|
| 1 | Die Desktop-Ära: Warum GUIs? | 🟢 Grundlagen | ✅ Abgeschlossen |
| 2 | AWT & Swing Grundlagen | 🟢 Grundlagen | ✅ Abgeschlossen |
| 3 | Layouts & Event-Handling | 🟢 Grundlagen | ✅ Abgeschlossen |
| 4 | Komplexe Swing-Komponenten | 🟡 Fortgeschritten | ✅ Abgeschlossen |
| 5 | JavaFX: Die „moderne“ Alternative | 🔴 KOPFNUSS | ✅ Abgeschlossen |
| → 6 | JDBC Grundlagen | 🟢 Grundlagen | 👉 DU BIST HIER! |
| 7 | JDBC Best Practices | 🟡 Fortgeschritten | 🔜 Kommt als nächstes |
| 8 | JPA Einführung | 🟢 Grundlagen | 🔒 Gesperrt |
| 9 | JPA CRUD & Queries | 🟡 Fortgeschritten | 🔒 Gesperrt |
| 10 | Integration & Ausblick | 🔴 KOPFNUSS | 🔒 Gesperrt |
Legende: 🟢 Einsteiger-freundlich | 🟡 Erfordert Grundlagen | 🔴 Optional/Anspruchsvoll
⚡ Das Wichtigste in 30 Sekunden
Was ist JDBC? Java Database Connectivity – die Standard-API um von Java aus mit Datenbanken zu sprechen.
Heute lernst du:
- ✅ Die JDBC-Architektur (Driver, Connection, Statement, ResultSet)
- ✅ Deine erste Datenbankverbindung
- ✅ CRUD-Operationen (Create, Read, Update, Delete)
- ✅ Warum PreparedStatement PFLICHT ist (SQL Injection!)
- ✅ try-with-resources für sauberes Ressourcen-Management
Die goldene Regel:
NIEMALS String-Konkatenation für SQL!
IMMER PreparedStatement mit Parametern!
🟢 GRUNDLAGEN: Die JDBC-Architektur
Wie Java mit Datenbanken spricht

Abbildung 1: JDBC – Die Schichten zwischen Java und Datenbank
JDBC funktioniert wie ein Dolmetscher:
- Dein Code spricht JDBC (java.sql.*)
- JDBC API ist die standardisierte Schnittstelle
- JDBC Driver übersetzt für die spezifische Datenbank
- Datenbank versteht ihre eigene Sprache
Der Clou: Dein Code bleibt gleich – nur der Treiber wechselt!
// MySQL String url = "jdbc:mysql://localhost:3306/mydb"; // PostgreSQL String url = "jdbc:postgresql://localhost:5432/mydb"; // H2 (In-Memory) String url = "jdbc:h2:mem:testdb"; // Der Rest deines Codes ändert sich NICHT! Connection conn = DriverManager.getConnection(url, user, pass);
🟢 Die 4 Schritte jeder JDBC-Operation

Abbildung 2: Die 4 Schritte – Connection → Statement → ResultSet → Close
Schritt 1: Connection herstellen
String url = "jdbc:h2:mem:testdb"; String user = "sa"; String password = ""; Connection conn = DriverManager.getConnection(url, user, password);
Schritt 2: Statement vorbereiten
// ❌ NIEMALS SO (SQL Injection!)
Statement stmt = conn.createStatement();
stmt.executeQuery("SELECT * FROM users WHERE id=" + userId);
// ✅ IMMER SO (PreparedStatement!)
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?"
);
ps.setInt(1, userId); // Parameter setzen
Schritt 3: ResultSet verarbeiten
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int alter = rs.getInt("alter");
System.out.println(name + " ist " + alter + " Jahre alt");
}
Schritt 4: Ressourcen schließen
// ALT: Manuell schließen (fehleranfällig!)
rs.close();
ps.close();
conn.close();
// NEU: try-with-resources (automatisch!)
try (Connection conn = DriverManager.getConnection(url, user, pass);
PreparedStatement ps = conn.prepareStatement(sql)) {
// Wird AUTOMATISCH geschlossen, auch bei Exceptions!
}
🔴 SQL Injection – Die #1 Sicherheitslücke

Abbildung 3: SQL Injection – Was passiert wenn du String-Konkatenation verwendest
Das Problem
// Benutzer gibt ein: ' OR '1'='1' -- String userInput = "' OR '1'='1' --"; // ❌ FALSCH: String-Konkatenation String sql = "SELECT * FROM users WHERE name='" + userInput + "'"; // Ergebnis: // SELECT * FROM users WHERE name='' OR '1'='1' --' // ↓ // Gibt ALLE Benutzer zurück!
Die Lösung
// ✅ RICHTIG: PreparedStatement String sql = "SELECT * FROM users WHERE name = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, userInput); // Ergebnis: // Sucht nach User mit Name "' OR '1'='1' --" // ↓ // Findet nichts (wie erwartet)
💀 SQL Injection ist seit 25 Jahren bekannt und IMMER NOCH der häufigste Angriff!
Verwende IMMER PreparedStatement!
🟡 PROFESSIONALS: CRUD komplett
CREATE – Daten einfügen
String sql = "INSERT INTO personen (name, alter, email) VALUES (?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
ps.setString(1, "Max Mustermann");
ps.setInt(2, 28);
ps.setString(3, "max@example.com");
int affected = ps.executeUpdate(); // Anzahl betroffener Zeilen
// Generierte ID abrufen
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
int newId = keys.getInt(1);
System.out.println("Neue ID: " + newId);
}
}
}
READ – Daten lesen
// Alle lesen
String sql = "SELECT id, name, alter, email FROM personen";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
// Verarbeiten...
}
}
// Nach ID suchen
String sql = "SELECT id, name, alter, email FROM personen WHERE id = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, suchId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
// Gefunden!
}
}
}
UPDATE – Daten ändern
String sql = "UPDATE personen SET name = ?, alter = ?, email = ? WHERE id = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "Neuer Name");
ps.setInt(2, 30);
ps.setString(3, "neu@example.com");
ps.setInt(4, personId);
int affected = ps.executeUpdate();
System.out.println(affected + " Zeile(n) aktualisiert");
}
DELETE – Daten löschen
String sql = "DELETE FROM personen WHERE id = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, personId);
int affected = ps.executeUpdate();
System.out.println(affected + " Zeile(n) gelöscht");
}
💬 Real Talk: Der erste Datenbank-Bug
Java Fleet Serverraum, Freitagabend.
Nova: „Franz-Martin, die App ist abgestürzt! Irgendwas mit ‚Too many connections‘?“
Franz-Martin: (seufzt) „Lass mich raten – du hast die Connections nicht geschlossen?“
Nova: „Ich… ich dachte die schließen sich von selbst?“
Franz-Martin: „Nope. Eine Connection ist wie eine Telefonleitung. Wenn du nicht auflegst, bleibt sie belegt.“
Nova: „Aber ich hab try-catch benutzt!“
Franz-Martin: „Zeig mal… Ah, da ist der Bug:“
try {
Connection conn = DriverManager.getConnection(url, user, pass);
// ... Code ...
conn.close(); // Wird bei Exception NICHT erreicht!
} catch (SQLException e) {
e.printStackTrace();
}
Nova: „Oh…“
Franz-Martin: „Klassiker. Wenn eine Exception fliegt, erreicht er conn.close() nie. Nach ein paar hundert Requests sind alle Connections weg.“
Nova: „Und die Lösung?“
Franz-Martin: „try-with-resources. Java 7, also kein Hexenwerk:“
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
// ... Code ...
} // conn.close() wird AUTOMATISCH aufgerufen, auch bei Exception!
Nova: „Das ist ja viel sauberer!“
Franz-Martin: „Und sicherer. Merk dir: Alles was AutoCloseable implementiert – Connection, Statement, ResultSet – gehört in try-with-resources.“
✅ Checkpoint
📝 Quiz
Frage 1: Was ist der Hauptgrund für PreparedStatement statt Statement?
A) PreparedStatement ist schneller
B) PreparedStatement verhindert SQL Injection
C) Statement ist veraltet
D) PreparedStatement kann mehr Datentypen
Frage 2: Was passiert wenn du eine Connection nicht schließt?
A) Nichts, Java schließt sie automatisch
B) Die Verbindung bleibt offen und blockiert Ressourcen
C) Die Datenbank stürzt ab
D) Die JVM beendet sich
Frage 3: Welche Methode ruft man für SELECT-Abfragen auf?
A) executeUpdate()
B) execute()
C) executeQuery()
D) executeSelect()
Frage 4: Was gibt executeUpdate() zurück?
A) Ein ResultSet
B) Die Anzahl der betroffenen Zeilen
C) true oder false
D) Die generierte ID
📝 Quiz-Lösungen
Frage 1: ✅ B – PreparedStatement verhindert SQL Injection
Das ist der wichtigste Grund. Performance-Vorteile gibt es auch, aber Sicherheit ist kritisch.
Frage 2: ✅ B – Die Verbindung bleibt offen
Jede Connection verbraucht Ressourcen. Nach vielen nicht-geschlossenen Connections: „Too many connections“.
Frage 3: ✅ C – executeQuery()executeQuery() für SELECT, executeUpdate() für INSERT/UPDATE/DELETE.
Frage 4: ✅ B – Die Anzahl der betroffenen Zeilen
Für die generierte ID: Statement.RETURN_GENERATED_KEYS + getGeneratedKeys().
❓ FAQ
Welche Datenbank soll ich zum Lernen verwenden?
H2 (In-Memory). Keine Installation, läuft im Speicher, perfekt zum Experimentieren. In Produktion: PostgreSQL oder MySQL/MariaDB.
Muss ich den JDBC-Treiber manuell laden?
Früher ja (Class.forName("com.mysql.jdbc.Driver")). Seit JDBC 4.0 (Java 6) nicht mehr – der Treiber registriert sich automatisch.
Wann Statement, wann PreparedStatement?
IMMER PreparedStatement wenn User-Input involviert ist. Statement nur für statische SQL-Befehle ohne Parameter.
Was ist der Unterschied zwischen execute(), executeQuery() und executeUpdate()?
executeQuery()→ für SELECT, gibt ResultSet zurückexecuteUpdate()→ für INSERT/UPDATE/DELETE, gibt Zeilenanzahl zurückexecute()→ für alles, gibt boolean zurück (true wenn ResultSet)
Warum nicht einfach JPA von Anfang an?
JPA baut auf JDBC auf. Wenn du JDBC verstehst, verstehst du auch was JPA im Hintergrund macht – und kannst Probleme debuggen.
📦 Downloads
| Projekt | Inhalt | Download |
|---|---|---|
| java-anwendungsentwicklung-tag6.zip | JDBC-Demos mit H2 | ⬇️ Download |
Quick Start:
mvn exec:java # Hallo JDBC mvn exec:java -Pcrud # CRUD-Beispiel mvn exec:java -Pinjection # SQL Injection Demo
🔗 Weiterführende Links
| Ressource | Beschreibung |
|---|---|
| JDBC Tutorial (Oracle) | Offizielle Dokumentation |
| H2 Database | Die In-Memory-Datenbank |
| SQL Injection (OWASP) | Sicherheits-Referenz |
🎉 Tag 6 geschafft!
Was du heute gelernt hast:
✅ JDBC-Architektur verstehen (Driver → Connection → Statement → ResultSet)
✅ try-with-resources für sauberes Ressourcen-Management
✅ CRUD-Operationen mit PreparedStatement
✅ SQL Injection verstehen und verhindern
✅ H2 als Lern-Datenbank verwenden
Morgen – Tag 7: JDBC Best Practices
Connection Pooling, Transaktionen, das DAO-Pattern. Von „funktioniert“ zu „produktionsreif“!
Fragen? franz-martin@java-developer.online
📚 Das könnte dich auch interessieren
© 2025 Java Fleet Systems Consulting | java-developer.online

