Zum Hauptinhalt springen

Woche 5, Tag 1 — Spring Data JPA Mental Model

Ziel

Heute verstehst du das Mental Model von Spring Data JPA.

Die Kernfragen:

  1. Welches Problem löst Spring Data JPA?
  2. Was ist JPA?
  3. Was ist Hibernate?
  4. Was ist Spring Data JPA?
  5. Was ist eine Entity?
  6. Was ist ein Repository?
  7. Was ist JpaRepository?
  8. Was ist EntityManager?
  9. Wie läuft der Datenbankzugriff in einer Spring-Boot-App ab?
  10. 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.
  • @Valid validiert Request-DTOs.
  • @RestControllerAdvice behandelt 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

KonzeptBedeutung
JPAJava-Spezifikation für Persistenz
HibernateImplementierung von JPA
Spring Data JPASpring-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:

@Entity bedeutet 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:

@GeneratedValue bedeutet, 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:

EntityDTO
Mappt auf DatenbanktabelleDefiniert API-Daten
Wird von Repository/JPA genutztWird von Controller/API genutzt
PersistenzmodellTransfermodell
Kann Beziehungen/Lazy Loading enthaltenSollte API-sicher sein
Sollte nicht direkt exponiert werdenGut 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:

EntityManager verwaltet 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

ThemaRepositoryEntityManager
Ebenehöhere Spring-Data-Abstraktionniedrigere JPA-API
Typische Nutzungnormales CRUD und Queriesindividuelle Persistenzlogik
Code-StilInterface-Methodenexplizite JPA-Operationen
Implementierunggenerierter ProxyJPA-Provider-Implementierung
Einsteiger-Nutzungsehr häufigseltener 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:

findById gibt 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. @Repository ist 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: @Repository ist 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:

WertBedeutung
noneSchema nicht verwalten
validateSchema gegen Entities validieren
updateSchema aktualisieren versuchen
createSchema beim Start droppen und neu erstellen
create-dropBeim 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

MethodeBedeutung
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 EntityManager und 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:

  1. Welche Annotation macht die Klasse zu einer JPA-Entity?
  2. Welche Annotation markiert den Primärschlüssel?
  3. Warum wird der No-Args-Konstruktor benötigt?
  4. Was bedeutet JpaRepository<TaskEntity, Long>?
  5. Wer erstellt die Repository-Implementierung?

Antworten:

  1. @Entity
  2. @Id
  3. JPA braucht ihn, um Entity-Instanzen zu erstellen.
  4. Das Repository verwaltet TaskEntity mit dem ID-Typ Long.
  5. 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-jpa fü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 @Entity und @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.
  • EntityManager ist die darunterliegende JPA-Kern-API.
  • Datenbank-Flow: Controller -> Service -> Repository -> EntityManager -> Hibernate -> Datenbank.
  • findById gibt Optional zurück, weil die Zeile möglicherweise nicht existiert.
  • @Entity ist kein Spring Bean.
  • Injiziere keine Services in Entities.
  • Nutze Migrationen für echte Produktions-Schema-Änderungen.