Spring Data, JDBC, JPA & Read Models
Repository-Methoden, Projections, Specifications, JdbcClient, CQRS-light und saubere Query-Grenzen.
Version 3SpringCodeDiagramm
In dieser Datei
Repository ist keine Abkürzung um Use Cases herum
Spring Data spart Code, aber Controller sollten nicht direkt Repositories orchestrieren. Der Use Case definiert, welche Daten fachlich gebraucht werden, und das Repository liefert eine passende Abfrage.
Read Model statt Entity-Leak
Listenansichten, Suchseiten und Reports brauchen selten komplette Aggregates. Projections oder eigene Read Models reduzieren Datenvolumen und verhindern Lazy-Loading-Fallen.
JPA und JDBC kombinieren
JPA eignet sich für Aggregate und transaktionale Änderungen. JDBC oder SQL-Projections sind oft klarer für komplexe Reports, Massenabfragen und optimierte Read-Modelle.
Entscheidungen
| Entscheidung | Gute Praxis | Prüffrage |
|---|---|---|
| Fachliche Grenze | Zuerst Use Case, Invariante und Verantwortlichkeit klären. | Welche Geschäftsentscheidung wird geschützt? |
| Technische Grenze | Framework-/Library-Code hinter Port, Adapter oder Konfiguration kapseln. | Kann die Domain ohne Framework getestet werden? |
| Betrieb | Timeouts, Logs, Metriken, Traces, Security und Rollback definieren. | Wie erkennt der Betrieb Fehler rechtzeitig? |
Ausführliche Beispiele
Projection für Listen-API
public interface OrderListProjection {
UUID getId();
String getCustomerNumber();
BigDecimal getTotalAmount();
Instant getCreatedAt();
}
interface OrderJpaRepository extends JpaRepository<OrderEntity, UUID> {
List<OrderListProjection> findByStatusOrderByCreatedAtDesc(OrderStatus status);
}
JdbcClient für explizites Read Model
public List<OrderListView> findOpenOrdersForDashboard() {
return jdbcClient.sql("""
select o.id, c.customer_number, o.total_amount, o.created_at
from orders o
join customers c on c.id = o.customer_id
where o.status = :status
order by o.created_at desc
limit 100
""")
.param("status", "OPEN")
.query(OrderListView.class)
.list();
}
Typische Stolperfallen
| Stolperfalle | Warum gefährlich |
|---|---|
| Derived Query wird Roman | Lange Methodennamen sind schwer wartbar. |
| Entity als API-Vertrag | Persistenzdetails werden öffentlich. |
| Keine Index-Strategie | Gute Java-Abfrage hilft nicht bei schlechter DB-Struktur. |