Spring Data JPA — Entities & Repositories
Datenbankzugriff mit Spring Data JPA
Spring Data JPA eliminiert Boilerplate: Interfaces werden zu Queries.
Lektion 21: Entities
@Entity
@Table(name = "products")
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank private String name;
@Positive private double price;
// getter/setter/constructors
}
Lektion 22: Repositories
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByCategory(String category);
List<Product> findByPriceLessThan(double price);
Optional<Product> findByName(String name);
}
Spring Data generiert die Implementation zur Laufzeit — kein SQL schreiben.
Lektion 23: Query-Methoden & @Query
@Query("SELECT p FROM Product p WHERE p.price BETWEEN :min AND :max")
List<Product> findByPriceRange(@Param("min") double min, @Param("max") double max);
// Sortierung & Pagination
Page<Product> findAll(Pageable pageable); // PageRequest.of(0, 20, Sort.by("price"))
Method-Name = Query
findByCategory wird zu WHERE category = ?. findByPriceLessThanOrderByPriceDesc
wird zu WHERE price < ? ORDER BY price DESC. Spring Data parst den Methodennamen
und generiert JPQL. Bei komplexen Queries: @Query("JPQL").
Lektion 24: Relationships
@Entity
public class Order {
@Id @GeneratedValue private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> items = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
private Customer customer;
}
Lektion 25: Pagination & Sorting
@GetMapping
public Page<Product> list(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return repo.findAll(PageRequest.of(page, size, Sort.by("name")));
}
N+1-Problem und Fetch-Typen
@ManyToOne und @OneToOne sind standardmäßig EAGER (sofort geladen).
@OneToMany und @ManyToMany sind LAZY (bei Zugriff). Iteriert man über
eine Liste und greift auf LAZY-Beziehungen zu, entstehen N+1 Queries —
eine pro Entity. Lösungen: @EntityGraph, JOIN FETCH in JPQL oder
@BatchSize.
Praxis-Szenario: CropGuard: Paginierte Plot-Liste
Ein Farmer mit 500 Flächen fordert GET /api/plots?insuredId=1&page=0&size=20. Ohne Pagination wären alle 500 Entities im Response — zu viel für Client und Speicher.
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren: