Woche 5, Tag 1 — Spring Data JPA Mental Model
Ziel
Heute verstehst du das Mental Model von Spring Data JPA.
Die Kernfragen:
- Welches Problem löst Spring Data JPA?
- Was ist JPA?
- Was ist Hibernate?
- Was ist Spring Data JPA?
- Was ist eine Entity?
- Was ist ein Repository?
- Was ist
JpaRepository? - Was ist
EntityManager? - Wie läuft der Datenbankzugriff in einer Spring-Boot-App ab?
- Welche typischen Prüfungsfallen gibt es?
1. Kurz-Wiederholung aus Woche 4
In Woche 4 hast du gelernt:
- Spring MVC mappt HTTP-Requests auf Java-Controller-Methoden.
- Controller sollten in der Regel schlank sein.
- Services enthalten die Business-Logik.
- DTOs definieren den API-Vertrag.
- REST-APIs sollten JPA-Entities in der Regel nicht direkt exponieren.
@Validvalidiert Request-DTOs.@RestControllerAdvicebehandelt Fehler global.
Merksatz:
Controller verarbeitet HTTP.
Service verarbeitet Business-Logik.
Repository verarbeitet Persistenz.
Heute startest du mit der Repository- und Persistenzschicht.
2. Das große Backend-Schichten-Bild
Eine typische Spring-Boot-REST-API hat Schichten:
Controller
↓
Service
↓
Repository
↓
Datenbank
Beispiel:
HTTP-Request
↓
TaskController
↓
TaskService
↓
TaskRepository
↓
PostgreSQL
Merksatz:
Controller sprechen mit Services. Services sprechen mit Repositories. Repositories sprechen mit der Datenbank.
3. Welches Problem löst Spring Data JPA?
Ohne Spring Data JPA würdest du viel repetitiven Datenbankcode schreiben.
Beispiel für repetitive Aufgaben:
Datenbankverbindung öffnen
SQL schreiben
Ergebniszeilen auf Java-Objekte mappen
Objekte speichern
Objekte aktualisieren
Objekte löschen
Transaktionen handhaben
Exceptions handhaben
Ressourcen schließen
Spring Data JPA hilft, Boilerplate zu reduzieren.
Du kannst Repository-Interfaces schreiben wie:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
und bekommst automatisch Methoden wie:
save()
findById()
findAll()
deleteById()
existsById()
count()
Merksatz:
Spring Data JPA reduziert repetitiven Datenbankzugriffscode.
4. Was ist JPA?
JPA steht für:
Java Persistence API
Einfache Definition:
JPA ist eine Java-Spezifikation zum Mapping von Java-Objekten auf relationale Datenbanktabellen.
JPA definiert Konzepte wie:
@Entity
@Id
@Table
@Column
@ManyToOne
@OneToMany
EntityManager
JPQL
Transaktionen
Persistence Context
Wichtig:
JPA ist eine Spezifikation — nicht die Implementierung selbst.
Merksatz:
JPA definiert die Regeln für Object-Relational Mapping in Java.
5. Was ist Hibernate?
Hibernate ist eine JPA-Implementierung.
Einfache Definition:
Hibernate ist die häufigste Implementierung von JPA.
Wenn JPA das Regelbuch ist, ist Hibernate der Motor, der das Regelbuch befolgt.
Mental Model:
JPA = Interface/Spezifikation
Hibernate = Implementierung/Provider
Beispiel:
JPA definiert:
@Entity
Hibernate versteht diese Annotation und mappt die Klasse auf eine Tabelle.
Merksatz:
JPA definiert. Hibernate implementiert.
6. Was ist Spring Data JPA?
Spring Data JPA ist ein Spring-Projekt, das JPA einfacher nutzbar macht.
Es baut auf JPA auf.
Es liefert Repository-Abstraktionen.
Einfache Definition:
Spring Data JPA stellt Repository-Interfaces und Query-Unterstützung auf Basis von JPA bereit.
Mit Spring Data JPA kannst du schreiben:
public interface UserRepository extends JpaRepository<UserEntity, Long> {
Optional<UserEntity> findByEmail(String email);
}
Spring implementiert dieses Repository zur Laufzeit automatisch.
Merksatz:
Spring Data JPA macht JPA einfacher, indem es Repository-Implementierungen generiert.
7. JPA vs. Hibernate vs. Spring Data JPA
| Konzept | Bedeutung |
|---|---|
| JPA | Java-Spezifikation für Persistenz |
| Hibernate | Implementierung von JPA |
| Spring Data JPA | Spring-Repository-Abstraktion auf Basis von JPA |
Merksatz:
JPA = Regeln
Hibernate = Motor
Spring Data JPA = Repository-Komfort
Beispiel-Flow:
Meine Repository-Methode
↓
Spring Data JPA
↓
JPA EntityManager
↓
Hibernate
↓
SQL
↓
Datenbank
8. Benötigte Dependency
Gradle:
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
Für PostgreSQL:
runtimeOnly("org.postgresql:postgresql")
Beispiel:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
runtimeOnly("org.postgresql:postgresql")
}
Wichtig:
Der JPA-Starter liefert JPA/Hibernate/Spring-Data-Unterstützung.
Der Datenbanktreiber verbindet mit der konkreten Datenbank.
Merksatz:
JPA-Starter ist nicht dasselbe wie ein Datenbanktreiber.
9. Grundkonfiguration
Beispiel application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: validate
show-sql: true
Wichtige Properties:
spring.datasource.url
spring.datasource.username
spring.datasource.password
spring.jpa.hibernate.ddl-auto
spring.jpa.show-sql
In echten Produktionsprojekten sollten Passwörter aus Umgebungsvariablen oder Secret Management kommen — nicht aus committetem YAML.
10. Was ist eine Entity?
Eine Entity ist eine Java-Klasse, die auf eine Datenbanktabelle gemappt ist.
Beispiel:
@Entity
@Table(name = "tasks")
public class TaskEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String status;
protected TaskEntity() {
}
public TaskEntity(String title, String status) {
this.title = title;
this.status = status;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getStatus() {
return status;
}
}
Diese Klasse mappt auf die Tabelle:
tasks
Merksatz:
Eine Entity ist ein Java-Objekt, das eine Datenbankzeile repräsentiert.
11. Entity und Tabelle
Entity:
@Entity
@Table(name = "tasks")
public class TaskEntity {
}
Datenbanktabelle:
CREATE TABLE tasks (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(255),
status VARCHAR(50)
);
Mapping:
TaskEntity -> Tabelle tasks
id -> Spalte id
title -> Spalte title
status -> Spalte status
12. @Entity
@Entity sagt JPA:
Diese Klasse soll als persistente Entity verwaltet werden.
Beispiel:
@Entity
public class UserEntity {
}
Ohne @Entity behandelt JPA die Klasse nicht als Datenbank-Entity.
Wichtig:
@Entity-Klassen werden von JPA verwaltet — nicht automatisch von Spring als normale Beans.
Das ist eine Prüfungsfalle.
Merksatz:
@Entitybedeutet JPA-verwaltete Persistenzklasse — kein Spring-Service-Bean.
13. @Table
@Table passt den Tabellennamen in der Datenbank an.
Beispiel:
@Entity
@Table(name = "app_users")
public class UserEntity {
}
Wenn du @Table nicht verwendest, nutzt JPA einen Standard-Tabellennamen basierend auf dem Klassennamen.
In echten Projekten sind explizite Tabellennamen oft klarer.
14. @Id
Jede Entity braucht einen Identifier.
Beispiel:
@Id
private Long id;
@Id markiert den Primärschlüssel.
Ohne ID kann JPA die Entity nicht ordentlich verwalten.
Merksatz:
Jede JPA-Entity braucht ein
@Id.
15. @GeneratedValue
@GeneratedValue sagt JPA, dass die ID generiert wird.
Beispiel:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Gängige Strategien:
IDENTITY
SEQUENCE
AUTO
TABLE
Für PostgreSQL ist SEQUENCE üblich.
Für einfache Beispiele ist IDENTITY leicht verständlich.
Merksatz:
@GeneratedValuebedeutet, dass die Datenbank oder der Provider die ID generiert.
16. Geschützter No-Args-Konstruktor
JPA-Entities brauchen einen No-Args-Konstruktor.
Beispiel:
protected TaskEntity() {
}
Warum?
JPA muss Entity-Instanzen per Reflection erstellen.
Er kann sein:
protected
public
protected ist oft bevorzugt, um versehentliche direkte Nutzung zu verhindern — JPA darf trotzdem instanziieren.
Merksatz:
JPA-Entities brauchen einen No-Args-Konstruktor.
17. Entity-Felder und Spalten
Standardmäßig mappen Felder auf Spalten.
Beispiel:
private String title;
mappt auf eine Spalte wie:
title
Anpassen mit @Column:
@Column(name = "task_title", nullable = false, length = 120)
private String title;
Bedeutung:
Spaltenname = task_title
nicht nullable
maximale Länge = 120
18. Entity vs. DTO
Entity:
@Entity
@Table(name = "tasks")
public class TaskEntity {
@Id
private Long id;
private String title;
private String status;
}
DTO:
public record TaskDto(
Long id,
String title,
String status
) {
}
Unterschied:
| Entity | DTO |
|---|---|
| Mappt auf Datenbanktabelle | Definiert API-Daten |
| Wird von Repository/JPA genutzt | Wird von Controller/API genutzt |
| Persistenzmodell | Transfermodell |
| Kann Beziehungen/Lazy Loading enthalten | Sollte API-sicher sein |
| Sollte nicht direkt exponiert werden | Gut für REST-Responses |
Merksatz:
Entity ist für die Datenbank. DTO ist für die API.
19. Was ist ein Repository?
Ein Repository ist ein Objekt, das Zugriff auf persistente Daten bietet.
Einfache Definition:
Ein Repository versteckt Datenbankzugriff hinter einem Interface.
Beispiel:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
Dieses Repository arbeitet mit:
TaskEntity
und dem ID-Typ:
Long
Merksatz:
Repository ist die Persistenz-Zugriffsschicht.
20. JpaRepository
JpaRepository ist ein Spring-Data-Interface mit vielen fertigen Methoden.
Beispiel:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
Es liefert Methoden wie:
save(entity)
findById(id)
findAll()
delete(entity)
deleteById(id)
existsById(id)
count()
flush()
Du musst grundlegendes CRUD also nicht manuell implementieren.
21. Repository-Typ-Parameter
JpaRepository<TaskEntity, Long>
bedeutet:
TaskEntity = Entity-Typ
Long = ID-Typ
Wenn die ID ein UUID ist:
public interface TaskRepository extends JpaRepository<TaskEntity, UUID> {
}
Merksatz:
JpaRepository<EntityType, IdType>.
22. Repository ist ein Spring Bean
Dieses Interface:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
wird zu einem Spring Bean.
Du kannst es also injizieren:
@Service
public class TaskService {
private final TaskRepository taskRepository;
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
}
Spring Data JPA erstellt zur Laufzeit eine Proxy-Implementierung.
Merksatz:
Spring Data erstellt Repository-Implementierungs-Proxies automatisch.
23. Repository-Proxy
Du schreibst:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
Spring erstellt:
Runtime-Proxy-Implementierung
Dieser Proxy behandelt Aufrufe wie:
taskRepository.findById(1L);
Im Hintergrund nutzt er JPA und EntityManager.
Merksatz:
Du schreibst das Repository-Interface. Spring Data liefert die Implementierung.
24. Was ist EntityManager?
EntityManager ist das zentrale JPA-Interface für die Interaktion mit dem Persistence Context.
Einfache Definition:
EntityManagerverwaltet JPA-Entities und kommuniziert über den JPA-Provider mit der Datenbank.
Er kann:
Entities persistieren
Entities finden
Entities mergen
Entities entfernen
Queries erstellen
Persistence Context verwalten
Änderungen flushen
Beispiel:
entityManager.find(TaskEntity.class, 1L);
Mit Spring Data JPA nutzt du aber oft Repositories statt EntityManager direkt.
Merksatz:
Repository ist das gängige Spring-Data-Interface. EntityManager ist die darunterliegende JPA-Kern-API.
25. Repository vs. EntityManager
| Thema | Repository | EntityManager |
|---|---|---|
| Ebene | höhere Spring-Data-Abstraktion | niedrigere JPA-API |
| Typische Nutzung | normales CRUD und Queries | individuelle Persistenzlogik |
| Code-Stil | Interface-Methoden | explizite JPA-Operationen |
| Implementierung | generierter Proxy | JPA-Provider-Implementierung |
| Einsteiger-Nutzung | sehr häufig | seltener direkt |
Merksatz:
Nutze Repositories für gängigen Datenzugriff. Nutze EntityManager für niedrigere, individuelle Fälle.
26. Datenbankzugriffs-Flow
Beispiel-Request:
GET /api/tasks/1
Ablauf:
1. Client sendet GET /api/tasks/1.
2. DispatcherServlet empfängt den Request.
3. TaskController.getTask(1) wird aufgerufen.
4. Controller ruft TaskService.findById(1) auf.
5. Service ruft TaskRepository.findById(1) auf.
6. Repository-Proxy nutzt EntityManager.
7. EntityManager nutzt Hibernate.
8. Hibernate generiert SQL.
9. Datenbank liefert die Zeile zurück.
10. Hibernate mappt die Zeile auf TaskEntity.
11. Service mappt TaskEntity auf TaskDto.
12. Controller gibt TaskDto zurück.
13. Jackson konvertiert TaskDto zu JSON.
Kurz-Merksatz:
Controller -> Service -> Repository -> EntityManager -> Hibernate -> Datenbank
27. Vollständiges Beispiel: Entity
@Entity
@Table(name = "tasks")
public class TaskEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String status;
protected TaskEntity() {
}
public TaskEntity(String title, String status) {
this.title = title;
this.status = status;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getStatus() {
return status;
}
public void complete() {
this.status = "DONE";
}
}
Wichtig:
Entity enthält Persistenzdaten und Domain-Verhalten.
28. Vollständiges Beispiel: Repository
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
List<TaskEntity> findByStatus(String status);
Optional<TaskEntity> findByTitle(String title);
boolean existsByTitle(String title);
}
Spring Data JPA erstellt Queries aus Methodennamen.
Beispiele:
findByStatus -> WHERE status = ?
findByTitle -> WHERE title = ?
existsByTitle -> prüft Existenz per Titel
Abgeleitete Queries schauen wir uns später im Detail an.
29. Vollständiges Beispiel: Service
@Service
public class TaskService {
private final TaskRepository taskRepository;
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
public TaskDto findById(Long id) {
TaskEntity task = taskRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Task", id));
return toDto(task);
}
public TaskDto create(CreateTaskRequest request) {
TaskEntity task = new TaskEntity(
request.title(),
"OPEN"
);
TaskEntity saved = taskRepository.save(task);
return toDto(saved);
}
private TaskDto toDto(TaskEntity entity) {
return new TaskDto(
entity.getId(),
entity.getTitle(),
entity.getStatus()
);
}
}
Service-Verantwortlichkeiten:
Business-Logik
Transaktionsgrenze
Repository-Koordination
Entity-zu-DTO-Mapping
Exception-Entscheidungen
30. Vollständiges Beispiel: Controller
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@GetMapping("/{id}")
public TaskDto get(@PathVariable Long id) {
return taskService.findById(id);
}
@PostMapping
public ResponseEntity<TaskDto> create(
@Valid @RequestBody CreateTaskRequest request
) {
TaskDto created = taskService.create(request);
URI location = URI.create("/api/tasks/" + created.id());
return ResponseEntity.created(location).body(created);
}
}
Controller-Verantwortlichkeiten:
HTTP-Mapping
Request lesen
Validierung auslösen
Status Codes
Delegation an Service
31. Vollständiges Beispiel: DTOs
public record CreateTaskRequest(
@NotBlank
@Size(max = 100)
String title
) {
}
public record TaskDto(
Long id,
String title,
String status
) {
}
Request-DTO:
was der Client sendet
Response-DTO:
was der Server zurückgibt
Entity:
was die Datenbank speichert
Merksatz:
Request-DTO, Entity und Response-DTO sind verschiedene Modelle mit verschiedenen Aufgaben.
32. Was passiert bei save()?
Beispiel:
TaskEntity task = new TaskEntity("Learn JPA", "OPEN");
TaskEntity saved = taskRepository.save(task);
Für eine neue Entity:
JPA fügt eine neue Zeile ein.
Für eine bestehende verwaltete Entity:
JPA aktualisiert die Zeile, wenn die Transaktion flushed.
Wichtig:
save() bedeutet nicht immer sofortiges SQL in genau dieser Zeile.
SQL-Ausführung kann passieren, wenn:
Transaktion committet
Flush passiert
Query erfordert Flush
Repository-Flush-Methode wird aufgerufen
Das schauen wir uns bei Transaktionen genauer an.
33. Optional von findById
findById gibt zurück:
Optional<TaskEntity>
Beispiel:
TaskEntity task = taskRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Task", id));
Warum Optional?
Die Zeile existiert möglicherweise nicht.
Mach das nicht:
taskRepository.findById(id).get();
weil das NoSuchElementException werfen kann.
Besser:
orElseThrow(...)
Merksatz:
findByIdgibt Optional zurück, weil die Entity möglicherweise nicht existiert.
34. @Repository
Spring-Data-Repository-Interfaces brauchen @Repository nicht immer.
Beispiel:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
Spring Data erkennt es und erstellt einen Bean.
Für individuelle Repository-Klassen kann @Repository genutzt werden.
Wichtiges Konzept:
@Repository markiert Persistenz-Komponenten und unterstützt Exception Translation.
Merksatz:
Spring-Data-Repositories werden automatisch erkannt.
@Repositoryist trotzdem das Persistenz-Stereotyp.
35. Exception Translation
Spring kann Persistenz-Exceptions in Spring's DataAccessException-Hierarchie übersetzen.
Beispiel:
datenbankspezifische Exception
↓
Spring DataAccessException
Warum nützlich?
konsistentes Exception-Modell
weniger datenbankanbieter-spezifischer Code
@Repository ist mit diesem Konzept der Persistenz-Exception-Translation verbunden.
Für die Zertifizierung:
Merke dir:
@Repositoryist ein Persistenz-Stereotyp und beteiligt sich an der Exception Translation.
36. Entity ist kein Spring Bean
Das ist wichtig.
@Service:
@Service
public class TaskService {
}
Das ist ein Spring Bean.
@Entity:
@Entity
public class TaskEntity {
}
Das ist eine JPA-Entity.
Es ist kein normales Singleton-Spring-Bean.
Injiziere keine Services in Entities so:
@Entity
public class TaskEntity {
@Autowired
private EmailService emailService;
}
Schlechte Idee.
Entities sollten in der Regel nicht von Spring-Services abhängen.
Merksatz:
Spring Beans werden von Spring verwaltet. Entities werden von JPA verwaltet.
37. Entity-Lifecycle vs. Bean-Lifecycle
Spring-Bean-Lifecycle:
vom Spring-Container erstellt
Dependencies injiziert
@PostConstruct
als Singleton/Prototype/etc. genutzt
Destroy-Callbacks
JPA-Entity-Lifecycle:
neu/transient
verwaltet/persistent
detached
entfernt
Verschiedene Welten.
Merksatz:
Bean-Lifecycle und Entity-Lifecycle sind nicht dasselbe.
Den Entity-Lifecycle schauen wir uns später genauer an.
38. ddl-auto
Spring-Boot-Property:
spring:
jpa:
hibernate:
ddl-auto: validate
Gängige Werte:
none
validate
update
create
create-drop
Bedeutung:
| Wert | Bedeutung |
|---|---|
none | Schema nicht verwalten |
validate | Schema gegen Entities validieren |
update | Schema aktualisieren versuchen |
create | Schema beim Start droppen und neu erstellen |
create-drop | Beim Start erstellen, beim Shutdown droppen |
Produktionswarnung:
Vermeide create/create-drop/update in Produktion — außer du weißt genau, was du tust.
In Produktion nutze Migrationen:
Flyway
Liquibase
Merksatz:
Nutze Migrationen für echte Schema-Änderungen.
39. Repository-Methodennamen
Spring Data JPA kann Queries aus Methodennamen erstellen.
Beispiel:
List<TaskEntity> findByStatus(String status);
bedeutet:
SELECT * FROM tasks WHERE status = ?
Konzept-Beispiele:
Optional<UserEntity> findByEmail(String email);
boolean existsByEmail(String email);
List<TaskEntity> findByStatusOrderByTitleAsc(String status);
List<TaskEntity> findByTitleContainingIgnoreCase(String keyword);
In der nächsten Lektion gehen wir tiefer.
Merksatz:
Spring Data kann Queries aus Repository-Methodennamen ableiten.
40. Individuelle Query mit @Query
Manchmal werden Methodennamen zu lang.
Dann nutze @Query.
Beispiel JPQL:
@Query("select t from TaskEntity t where t.status = :status")
List<TaskEntity> findTasksByStatus(@Param("status") String status);
JPQL nutzt Entity-Namen und Felder — nicht Tabellennamen und Spalten.
SQL nutzt Tabellennamen und Spalten.
Merksatz:
JPQL spricht über Entities. SQL spricht über Tabellen.
41. Repository-Rückgabetypen
Gängige Rückgabetypen:
Optional<TaskEntity>
List<TaskEntity>
Page<TaskEntity>
Slice<TaskEntity>
boolean
long
void
Beispiele:
Optional<TaskEntity> findById(Long id);
List<TaskEntity> findByStatus(String status);
boolean existsByTitle(String title);
long countByStatus(String status);
Pagination schauen wir uns später an.
42. Gängige CRUD-Methoden
| Methode | Bedeutung |
|---|---|
save(entity) | Entity einfügen oder aktualisieren |
findById(id) | Eine Entity per ID finden |
findAll() | Alle Entities finden |
delete(entity) | Entity löschen |
deleteById(id) | Per ID löschen |
existsById(id) | Existenz prüfen |
count() | Zeilen zählen |
Wichtig:
Repository-Methoden arbeiten standardmäßig mit Entities — nicht mit DTOs.
43. Warum Services Repositories nutzen sollten
Schlecht:
@RestController
public class TaskController {
private final TaskRepository taskRepository;
@GetMapping("/api/tasks/{id}")
public TaskEntity get(@PathVariable Long id) {
return taskRepository.findById(id).orElseThrow();
}
}
Probleme:
Controller spricht direkt mit der Datenbankschicht
Business-Logik wandert möglicherweise in den Controller
Entities werden direkt exponiert
schwerer zu testen
weniger Separation of Concerns
Besser:
Controller -> Service -> Repository
Merksatz:
Controller sollten in echten Anwendungen nicht direkt Repositories aufrufen.
44. Wo sollte Mapping passieren?
Gängige Stile:
Service mappt Entity auf DTO
dedizierter Mapper mappt Entity auf DTO
Repository liefert in Spezialfällen Projections
Einfacher Stil zum Lernen:
private TaskDto toDto(TaskEntity entity) {
return new TaskDto(
entity.getId(),
entity.getTitle(),
entity.getStatus()
);
}
Halte Mapping am Anfang explizit.
Merksatz:
Konvertiere Entities zu DTOs, bevor du sie aus der API zurückgibst.
45. Typische Prüfungsfallen
Prüfungsfalle 1
JPA ist nicht dasselbe wie Hibernate.
JPA = Spezifikation
Hibernate = Implementierung
Prüfungsfalle 2
Spring Data JPA ist nicht dasselbe wie JPA.
Spring Data JPA = Repository-Abstraktion auf Basis von JPA
Prüfungsfalle 3
@Entity macht eine Klasse nicht zu einem Spring Bean.
@Entity = JPA-verwaltet
@Service/@Component = Spring-verwaltet
Prüfungsfalle 4
Jede Entity braucht ein @Id.
Prüfungsfalle 5
JPA-Entities brauchen einen No-Args-Konstruktor.
Prüfungsfalle 6
Repository arbeitet standardmäßig mit Entities — nicht mit DTOs.
Prüfungsfalle 7
JpaRepository<TaskEntity, Long> bedeutet Entity-Typ und ID-Typ.
Prüfungsfalle 8
Spring Data erstellt Repository-Implementierungen automatisch.
Prüfungsfalle 9
findById gibt Optional zurück, weil die Zeile möglicherweise nicht existiert.
Prüfungsfalle 10
Exponiere Entities in den meisten echten Projekten nicht direkt aus REST-Controllern.
Prüfungsfalle 11
ddl-auto=update ist in Produktion kein Ersatz für echte Migrationen.
Prüfungsfalle 12
JPQL nutzt Entity-Namen und Felder — nicht Tabellennamen und Spalten.
46. Echte Prüfungsfrage: JPA
Frage:
Was ist JPA?
Antwort:
JPA ist die Java Persistence API. Es ist eine Java-Spezifikation zum Mapping von Java-Objekten auf relationale Datenbanktabellen und zur Verwaltung von Persistenz.
47. Echte Prüfungsfrage: Hibernate
Frage:
Was ist Hibernate?
Antwort:
Hibernate ist eine JPA-Implementierung. Es liefert die eigentliche Persistenz-Engine, die Entities auf Datenbanktabellen mappt und SQL ausführt.
48. Echte Prüfungsfrage: Spring Data JPA
Frage:
Was ist Spring Data JPA?
Antwort:
Spring Data JPA ist ein Spring-Projekt, das Repository-Abstraktionen und Query-Unterstützung auf Basis von JPA bereitstellt. Es reduziert Boilerplate-Datenbankzugriffscode, indem es Repository-Implementierungen automatisch generiert.
49. Echte Prüfungsfrage: Entity
Frage:
Was ist eine JPA-Entity?
Antwort:
Eine JPA-Entity ist eine Java-Klasse, die auf eine Datenbanktabelle gemappt ist. Jede Entity-Instanz repräsentiert in der Regel eine Zeile in dieser Tabelle.
50. Echte Prüfungsfrage: Repository
Frage:
Was ist ein Repository?
Antwort:
Ein Repository ist eine Persistenz-Zugriffsabstraktion, die Datenbankzugriff hinter einem Interface versteckt.
51. Echte Prüfungsfrage: JpaRepository
Frage:
Was bedeutet JpaRepository<TaskEntity, Long>?
Antwort:
Es bedeutet, dass das Repository TaskEntity-Objekte verwaltet und der ID-Typ Long ist.
52. Echte Prüfungsfrage: EntityManager
Frage:
Was ist EntityManager?
Antwort:
EntityManager ist das zentrale JPA-Interface, das Entity-Instanzen verwaltet und über den JPA-Provider mit dem Persistence Context und der Datenbank interagiert.
53. Echte Prüfungsfrage: Entity vs. Spring Bean
Frage:
Ist eine @Entity ein Spring Bean?
Antwort:
Nein. Eine @Entity wird von JPA als Persistenzobjekt verwaltet. Sie ist kein normales Spring Bean wie @Service oder @Component.
54. Echte Prüfungsfrage: findById
Frage:
Warum gibt findById Optional zurück?
Antwort:
Weil die Entity mit dieser ID möglicherweise nicht existiert.
55. Echte Prüfungsfrage: DTO vs. Entity
Frage:
Warum sollten REST-APIs in der Regel DTOs statt Entities zurückgeben?
Antwort:
DTOs vermeiden das Exponieren interner Datenbankstrukturen, verhindern das Leaken sensibler Felder, vermeiden Lazy-Loading- und Serialisierungsprobleme und halten den API-Vertrag vom Persistenzmodell getrennt.
56. Interview-Antwort
Frage:
Erkläre den Unterschied zwischen JPA, Hibernate und Spring Data JPA.
Gute Antwort:
JPA ist die Java-Spezifikation für Persistenz und Object-Relational Mapping. Hibernate ist eine gängige Implementierung dieser Spezifikation. Spring Data JPA ist eine Spring-Abstraktion auf Basis von JPA, die Repository-Interfaces, generierte Implementierungen, abgeleitete Queries und Spring-Integration bereitstellt. Kurz: JPA definiert die Regeln, Hibernate implementiert sie, und Spring Data JPA macht sie einfacher nutzbar.
57. Interview-Antwort
Frage:
Was ist eine JPA-Entity?
Gute Antwort:
Eine JPA-Entity ist eine Java-Klasse, die auf eine relationale Datenbanktabelle gemappt ist. Sie ist mit @Entity annotiert, hat einen Identifier mit @Id markiert und braucht für JPA in der Regel einen No-Args-Konstruktor. Jede Entity-Instanz repräsentiert in der Regel eine Zeile in der Tabelle. Entities werden von JPA verwaltet — nicht als normale Singleton-Spring-Beans.
58. Interview-Antwort
Frage:
Was ist ein Spring-Data-Repository?
Gute Antwort:
Ein Spring-Data-Repository ist ein Interface, das Datenbankzugriffsmethoden für eine Entity bereitstellt. Ein Interface, das JpaRepository<TaskEntity, Long> erweitert, bekommt zum Beispiel automatisch Methoden wie save, findById, findAll und deleteById. Spring Data erstellt eine Runtime-Proxy-Implementierung — du schreibst die Implementierung also in der Regel nicht manuell.
59. Interview-Antwort
Frage:
Was ist
EntityManagerund nutzt du ihn direkt?
Gute Antwort:
EntityManager ist das zentrale JPA-Interface zur Verwaltung von Entities und Interaktion mit dem Persistence Context. Er kann Entities persistieren, finden, mergen, entfernen und Queries erstellen. In normalen Spring-Data-JPA-Anwendungen nutze ich Repositories für gängigen Datenzugriff. EntityManager nutze ich direkt nur für niedrigere oder individuelle Persistenzfälle.
60. Interview-Antwort
Frage:
Erkläre den Datenbankzugriffs-Flow in einer Spring-Boot-REST-API.
Gute Antwort:
Ein Request erreicht zuerst den Controller über Spring MVC. Der Controller delegiert an einen Service. Der Service enthält die Business-Logik und ruft ein Spring-Data-JPA-Repository auf. Das Repository ist ein von Spring Data generierter Proxy und nutzt darunter JPA's EntityManager. Der JPA-Provider — meist Hibernate — generiert SQL und spricht mit der Datenbank. Das Ergebnis wird auf eine Entity gemappt und dann in der Regel zu einem DTO konvertiert, bevor es an den Controller zurückgeht.
61. Kleine Code-Übung
Entity erstellen:
@Entity
@Table(name = "tasks")
public class TaskEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String status;
protected TaskEntity() {
}
public TaskEntity(String title, String status) {
this.title = title;
this.status = status;
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getStatus() {
return status;
}
}
Repository erstellen:
public interface TaskRepository extends JpaRepository<TaskEntity, Long> {
}
Fragen:
- Welche Annotation macht die Klasse zu einer JPA-Entity?
- Welche Annotation markiert den Primärschlüssel?
- Warum wird der No-Args-Konstruktor benötigt?
- Was bedeutet
JpaRepository<TaskEntity, Long>? - Wer erstellt die Repository-Implementierung?
Antworten:
@Entity@Id- JPA braucht ihn, um Entity-Instanzen zu erstellen.
- Das Repository verwaltet
TaskEntitymit dem ID-TypLong. - Spring Data JPA erstellt eine Runtime-Proxy-Implementierung.
62. Kleine Bug-Übung 1
Problem:
@Entity
public class TaskEntity {
private Long id;
private String title;
}
Frage:
Was fehlt?
Antwort:
@Id fehlt. Jede JPA-Entity braucht einen Identifier.
Fix:
@Id
private Long id;
63. Kleine Bug-Übung 2
Problem:
@Entity
public class TaskEntity {
@Id
private Long id;
public TaskEntity(String title) {
this.title = title;
}
private String title;
}
Frage:
Was fehlt?
Antwort:
Ein No-Args-Konstruktor fehlt. JPA braucht ihn.
Fix:
protected TaskEntity() {
}
64. Kleine Bug-Übung 3
Problem:
@Entity
public class TaskEntity {
@Autowired
private EmailService emailService;
}
Frage:
Was ist falsch?
Antwort:
Entities werden von JPA verwaltet — nicht als normale Spring Beans. Injiziere keine Spring-Services in Entities. Business-Operationen, die Services brauchen, gehören in der Regel in die Service-Schicht.
Übungsfragen
Frage 1
Welches Problem löst Spring Data JPA?
Antwort:
Spring Data JPA reduziert repetitiven Datenbankzugriffscode durch Repository-Abstraktionen und automatisch generierte Repository-Implementierungen.
Frage 2
Was ist JPA?
Antwort:
JPA ist die Java Persistence API — eine Java-Spezifikation zum Mapping von Java-Objekten auf relationale Datenbanktabellen und zur Verwaltung von Persistenz.
Frage 3
Was ist Hibernate?
Antwort:
Hibernate ist eine gängige Implementierung der JPA-Spezifikation.
Frage 4
Was ist Spring Data JPA?
Antwort:
Spring Data JPA ist ein Spring-Projekt, das Repository-Abstraktionen und Query-Unterstützung auf Basis von JPA bereitstellt.
Frage 5
Was ist der Unterschied zwischen JPA, Hibernate und Spring Data JPA?
Antwort:
JPA ist die Spezifikation. Hibernate ist eine Implementierung dieser Spezifikation. Spring Data JPA ist eine Spring-Abstraktion, die JPA über Repositories einfacher nutzbar macht.
Frage 6
Welche Dependency fügt Spring-Data-JPA-Unterstützung hinzu?
Antwort:
Nutze:
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
Frage 7
Brauchst du trotzdem einen Datenbanktreiber?
Antwort:
Ja. Du brauchst weiterhin einen Datenbanktreiber wie PostgreSQL, MySQL oder MariaDB.
Frage 8
Was ist eine Entity?
Antwort:
Eine Entity ist eine Java-Klasse, die auf eine Datenbanktabelle gemappt ist. Jede Entity-Instanz repräsentiert in der Regel eine Zeile.
Frage 9
Was macht @Entity?
Antwort:
@Entity sagt JPA, dass die Klasse eine persistente Entity ist.
Frage 10
Was macht @Id?
Antwort:
@Id markiert den Primärschlüssel der Entity.
Frage 11
Warum braucht eine JPA-Entity einen No-Args-Konstruktor?
Antwort:
JPA braucht einen No-Args-Konstruktor, um Entity-Instanzen per Reflection zu erstellen.
Frage 12
Was ist ein Repository?
Antwort:
Ein Repository ist eine Persistenz-Zugriffsabstraktion, die Datenbankzugriff hinter einem Interface versteckt.
Frage 13
Was bedeutet JpaRepository<TaskEntity, Long>?
Antwort:
Es bedeutet, dass das Repository TaskEntity-Objekte verwaltet und der ID-Typ Long ist.
Frage 14
Wer erstellt die Repository-Implementierung?
Antwort:
Spring Data JPA erstellt automatisch eine Runtime-Proxy-Implementierung.
Frage 15
Was ist EntityManager?
Antwort:
EntityManager ist das zentrale JPA-Interface zur Verwaltung von Entities und Interaktion mit dem Persistence Context und der Datenbank über den JPA-Provider.
Frage 16
Was ist der Unterschied zwischen Repository und EntityManager?
Antwort:
Ein Repository ist eine höhere Spring-Data-Abstraktion für gängigen Datenzugriff. EntityManager ist die darunterliegende niedrigere JPA-API.
Frage 17
Wie läuft der Datenbankzugriffs-Flow vom Controller zur Datenbank ab?
Antwort:
Der Flow ist: Controller ruft Service auf, Service ruft Repository auf, Repository nutzt EntityManager, EntityManager nutzt Hibernate, Hibernate generiert SQL und spricht mit der Datenbank.
Frage 18
Warum gibt findById Optional zurück?
Antwort:
Weil die Entity mit dieser ID möglicherweise nicht existiert.
Frage 19
Ist eine Entity ein Spring Bean?
Antwort:
Nein. Eine Entity wird von JPA verwaltet — nicht als normales Singleton-Spring-Bean.
Frage 20
Warum sollten REST-APIs in der Regel DTOs statt Entities zurückgeben?
Antwort:
DTOs vermeiden das Exponieren interner Datenbankstrukturen, sensibler Felder, Lazy-Loading-Probleme und Serialisierungsprobleme. Sie halten den API-Vertrag vom Persistenzmodell getrennt.
Merksätze zum Mitnehmen
- Spring Data JPA reduziert Datenbank-Boilerplate.
- JPA ist die Persistenz-Spezifikation.
- Hibernate ist eine JPA-Implementierung.
- Spring Data JPA ist eine Repository-Abstraktion auf Basis von JPA.
- JPA definiert, Hibernate implementiert, Spring Data JPA vereinfacht.
spring-boot-starter-data-jpafügt JPA-Unterstützung hinzu.- Ein Datenbanktreiber wird trotzdem benötigt.
- Eine Entity ist eine Java-Klasse, die auf eine Datenbanktabelle gemappt ist.
- Jede Entity braucht
@Entityund@Id. - JPA-Entities brauchen einen No-Args-Konstruktor.
- Entity ist für die Datenbank. DTO ist für die API.
- Repository versteckt Datenbankzugriff.
JpaRepository<Entity, Id>definiert Entity-Typ und ID-Typ.- Spring Data erstellt Repository-Proxy-Implementierungen.
EntityManagerist die darunterliegende JPA-Kern-API.- Datenbank-Flow: Controller -> Service -> Repository -> EntityManager -> Hibernate -> Datenbank.
findByIdgibt Optional zurück, weil die Zeile möglicherweise nicht existiert.@Entityist kein Spring Bean.- Injiziere keine Services in Entities.
- Nutze Migrationen für echte Produktions-Schema-Änderungen.