Spring Data JPA oferuje zaawansowane narzędzia do zarządzania repozytoriami danych w ramach Java Persistence API
(JPA). Kluczową korzyścią tego rozwiązania jest uproszczenie procesu dostępu do danych. Przykładowo, mając tabelę w
bazie danych z odpowiadającą jej encją Hibernate, możemy natychmiastowo ją wykorzystywać. Spring Data JPA eliminuje
potrzebę tworzenia od podstaw standardowych operacji bazodanowych, takich jak CRUD. System dostarcza predefiniowane
interfejsy z zestawem podstawowych metod dostępowych, co umożliwia efektywne tworzenie, usuwanie oraz modyfikowanie
rekordów bez nadmiernego obciążania kodu aplikacji.
Jako entuzjaści Spring Boot, wprowadzamy konfigurację szablonu startowego, która zapewnia nam niezbędny
zestaw zależności. W tej części kursu opieramy się na Spring Boot w wersji 1.x, który jest
kompatybilny ze Spring Data JPA.
W rozdziale
Spring
Data JPA 2 / 3 - Podstawy przedstawiamy wersję dla Spring Boot 2 / 3. Różnice nie są duże.
Polegają głównie na wprowadzeniu udogodnień znanych
z Javy 8 oraz na zmianie nazewnictwa niektórych metod
find (ale o tym szerzej we
wspomnianym rozdziale).
Wracając do meritum, tak wygląda nasza zależność szablonu startowego
spring-boot-starter-data-jpa:
Po zbudowaniu projektu możemy przystąpić do przyjrzenia się kilku istotnym interfejsom, które dostajemy razem ze starterem.
Będziemy z nich korzystać (w szczególności z jednego z nich) podczas wykonywania operacji na danych w systemie.
Podstawowy interfejs - CrudRepository
Dostarcza podstawowe wersje metod dla operacji typu CRUD (Create, Read, Update, Delete):
Wytłumaczenie kolejnych kategorii metod wydaje się być zwykłą formalnością, ale podsumujmy:
save |
- zapisuje encje w bazie (pojedynczo lub cały zbiór) |
findOne |
- wyszukuje encje po id |
exists |
- sprawdza po id czy encja istnieje |
findAll |
- pobiera wszystkie encje zwracając interfejs Iterable |
count |
- zlicza wszystkie encje |
delete |
- usuwa encje po podanym obiekcie lub zbiorze obiektów |
deleteAll |
- usuwa wszystkie encje |
|
|
PagingAndSortingRepository rozszerzający CrudRepository
Dorzuca - w stosunku do tego co ma
CrudRepository - metody wyciągające encje w sposób posortowany i stronicowany:
Metody te rozumiemy w ten sposób:
findAll(Sort sort) |
- pobiera wszystkie encje (z uwzględnieniem sortowania) i zwraca interfejs Iterable |
findAll(Pageable pageable) |
- pobiera wszystkie encje (z uwzględnieniem stronicowania) i zwraca interfejs strony: Page |
JPARepository rozszerzający PagingAndSortingRepository
Dostarcza bardziej precyzyjne wersje metod, np. poprzez zwracanie interfejsu
List zamiast
Iterable
oraz dodaje nowe metody:
W tym przypadku wytłumaczenie kolejnych kategorii metod wygląda tak:
findAll |
- pobiera wszystkie encje (ew. sortowane), albo encje po zbiorze idików i zwraca interfejs List |
save |
- zapisuje encje w bazie, podane w postaci zbioru bazującego na interfejsie Iterable |
flush |
- wymusza odzwierciedlenie wykonanych operacji (na encjach) na bazie |
saveAndFlush |
- zapisuje encje i wymusza odzwierciedlenie wykonanych operacji (na encjach) na bazie |
deleteInBatch |
- usuwa całą partię encji, podaną w postaci zbioru bazującego na interfejsie Iterable |
deleteAllInBatch |
- usuwa wszystkie encje w jednej partii |
getOne |
- pobiera encję po id |
findAll(Example...) |
- pobiera encje po podanej klasie przykładu (możliwe w wersji z sortowaniem) |
Zatrzymajmy się w tym miejscu na chwilę, aby zauważyć jedną rzecz. Dwie ostatnie metody, pobierające obiekty po klasie przykładu (
Example),
znajdują się w tym interfejsie nieprzypadkowo, mimo iż mają niewiele wspólnego z dziedziczonymi klasami. Okazuje się bowiem, że
interfejs
JPARepository dziedziczy nie tylko z
PagingAndSortingRepository, ale
również z interfejsu
QueryByExampleExecutor. Ten ostatni jest odpowiedzialny za dostarczenie deklaracji metod
operujących właśnie na klasie przykładu.
JPARepository w akcji
No dobrze, zobaczmy zatem teraz przykład, który zobrazuje nam dokładnie jak działa
JPARepository. Mamy klasę
ItemServiceImpl implementującą doskonale znany nam już interfejs
ItemService (znany dla czytających rozdziały po koleji ;)).
Mamy również interfejs, za pomocą którego będziemy wykonywać operacje na itemach. Interfejs ten dziedziczy z
JPARepository i..nie posiada własnych metod (jedynie dziedziczy metody):
Wstrzykujemy obiekt interfejsu
ItemRepository do naszego serwisu
ItemServiceImpl i już możemy używać metod,
które są dostępne wśród wszystkich dziedziczonych przez nas interfejsów (
ItemRepository -
JPARepository
-
PagingAndSortingRepository -
CrudRepository).
Dla naszego interfejsu określiliśmy również dwa parametry typu. Pierwszy -
Item, wskazuje na klasę encji, a drugi -
Long, reprezentuje typ klucza jaki jest używany przez encję
Item.
Możemy teraz w naszym serwisie zdefiniować metodę do pobierania itemu po id (
getAppaItem) i wykonać w niej operację
pobrania
encji po id:
Oczywiście nasz interfejs nie musi być pusty. W miarę potrzeby możemy do niego dokładać własne metody, a nawet tworzyć całe zapytania, ale o tym już w kolejnych rozdziałach.
Na koniec zobaczmy jeszcze jak wygląda zbiorcza lista metod, jakie możemy wykonać na naszym
ItemRepository, zgodnie z tym co pisaliśmy o dziedziczeniu interfejsów:
Rekomendacja
W projekcie można zaimplementować każdy z powyższych interfejsów, niemniej ze względu na to, że interfejs JPARepository
ma najszerszy zakres, warto od samego początku używać własnie jego. Nawet jeśli w początkowej fazie wydaje się nam, że nie będziemy potrzebować sortowania, stronicowania,
bądź też operowania na klasie przykładu, to prędzej czy później przychodzi taki czas, że projekt się rozrasta, a początkowe założenia się zmieniają
i nagle może być wymagane dodanie wspomnianych funkcjonalności. Profesjonalni programiści powinni być na to przygotowani już wcześniej, prawda?
Praktyka
W każdym z naszych kursów poświęconych Springowi, kod działa na poziomie warstw kontrolera, serwisu i
repozytorium. Wszystkie klasy serwisowe są wyposażone w wstrzyknięte interfejsy, które umożliwiają wykonanie
potrzebnych operacji.
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Czy informacje, które otrzymałeś, były pomocne?
Jeśli tak, zapraszam Cię do podarowania mi kawy.
[TEORIA i PRAKTYKA] Strefa doładowania wiedzy
W tej strefie znajdziesz wszystko co niezbędne, aby komfortowo uczyć się Hibernate'a.
Doskonale opisany kod nie zawiera zbędnych komplikacji, tylko samą esencję w postaci praktycznych przykładów.
Tutaj odnajdziesz wszystko co jest istotne w danym temacie. Otrzymujesz pakiet złożony z kilku projektów
wraz z obszernym wytłumaczeniem kodu.
Topowe Materiały
Spring IO: Spring Data
Baeldung: Introduction to Spring Data JPA
Udemy: [NEW] Spring Boot 3, Spring 6 & Hibernate for Beginners — polskie napisy