W sytuacjach, gdzie ani zapytania wbudowane, ani własne nie spełniają oczekiwań, zapytania natywne mogą stanowić
skuteczną alternatywę. Te zapytania, choć prostsze w idei, oferują znacznie szersze
możliwości.
W skrócie, zapytania natywne pozwalają na bezpośrednie włączenie standardowego zapytania SQL
do adnotacji
@Query, zamiast wykorzystania JPQL.
Dzięki temu, operacje są przeprowadzane bezpośrednio na tabelach, a nie na encjach, co
daje większą swobodę działania. Korzystając z zapytań natywnych, mamy dostęp do pełnego spektrum możliwości języka
SQL, bez ograniczeń narzuconych przez JPQL, co pozwala na bardziej zaawansowane i skomplikowane operacje na danych.
Zapytanie grupujące jako Native Query
Załóżmy, że naszym zadaniem jest opracowanie zapytania umożliwiającego prezentację statystyk dotyczących liczby
itemów, podzielonych według określonych kategorii. Aby sprostać temu wyzwaniu, potrzebne będzie skonstruowanie
zapytania grupującego, wykorzystującego klauzulę
GROUP BY.
To zapytanie będzie realizowane w ramach kontrolowanego
przez
JPARepository. Oznacza to, że będziemy tworzyć złożoną konstrukcję, która pozwoli na efektywne
gromadzenie i prezentowanie danych w sposób uporządkowany i przystępny dla użytkowników.
Podobnie jak to miało miejsce w przypadku zapytań własnych, tak samo w przypadku zapytań natywnych,
podczas tworzenia takiego zapytania należy zwrócić uwagę na kilka aspektów:
- Parametry wykorzystywane w tekście zapytania poprzedzamy dwukropkiem, np.: :lastName
- Domyślnie parametry metody są przyporządkowane do parametrów z treści zapytania na podstawie kolejności miejsc, więc możemy NIE oznaczać parametrów metody za pomocą adnotacji @Param.
Takie podejście bywa jednak problematyczne, w przypadku ewentualnych zmian w metodzie w przyszłości, szczególnie w przypadku refactoringu.
- Stosujemy adnotację @Param, aby przyporządkować parametry metody do parametrów z treści zapytania na podstawie nazwy przekazanej do adnotacji. Nazwa
musi zgadzać się z nazwą użytą w treści zapytania (po dwukropku). Nie jest wtedy wymagana zgodność co do kolejności parametrów.
- W przypadku gdy chcemy dodać do zapytania opcje stronicowania Pageable lub sortowania Sort, dodajemy te typy
na ostatniej pozycji wśród parametrów metody. Tutaj jedna uwaga. W przypadku użycia interfejsu do stronicowania w ramach zapytań natywnych, jesteśmy zobowiązani do podania
zapytania zliczającego w ramach adnotacji @Query:
Na koniec tego wątku musimy wspomnieć o bardzo ważnej rzeczy, która może się wydawać niejasna patrząc na powyższe zapytanie.
Dotyczy ona zwrotu /*#pageable*/, który został dodany do zapytania jako workaround, aby takie zapytanie w ogóle zadziałało.
Okazuje się bowiem, że Spring Data JPA przed wersją 2.x posiada błąd, który skutkuje tym, że podając w metodzie jako parametr interfejs Pageable
nie jesteśmy w stanie takiego zapytania w ogóle uruchomić. Otrzymujemy błąd:
Jest to o tyle nielogiczne, że w oficjalnej dokumentacji Springa jest napisane, że o ile dynamiczne sortowanie nie jest wspierane,
o tyle można użyć natywnych zapytań do paginacji poprzez podanie własnego zapytania COUNT oraz dodanie Pageable jako parametru metody.
Okazuje się jednak, że z powodu błędnie zaimplementowanego kodu klasy NativeJpaQuery wymagane jest dodatkowo posiadanie wspomnianego tekstu w treści zapytania:
Powyższy błąd został naprawiony przez programistów Springa dopiero w wersji 2.0.4 w marcu 2018 roku.
Zapytanie typu UPDATE lub DELETE
Podobnie jak to miało miejsce w przypadku zapytań własnych (
Spring
Data JPA - Zapytania własne), natywne zapytania modyfikujące również wymagają dodania adnotacji:
@Modifying i
@Transactional.
Rekomendacja
Zapytania natywne stanowią wyjątkowo efektywne narzędzie do rozwiązywania wielu problemów, jednak ważne jest,
aby być świadomym pewnych ograniczeń, szczególnie w kontekście przenoszenia aplikacji między różnymi systemami
zarządzania bazami danych. Wykorzystanie czystego SQL-a może prowadzić do wprowadzenia elementów specyficznych
dla konkretnej bazy danych, na przykład Oracle, które są zgodne ze standardem SQL, ale niekoniecznie
kompatybilne z innymi systemami, takimi jak PostgreSQL.
Taka sytuacja może skutkować tym, że po przeniesieniu
aplikacji niektóre zapytania mogą nie działać poprawnie lub w ogóle przestać funkcjonować. Dlatego rekomendujemy
ograniczenie stosowania zapytań natywnych do minimum albo przynajmniej zachowanie pełnej świadomości
potencjalnych konsekwencji, jakie niesie za sobą to rozwiązanie.
Praktyka
Zapytania natywne są przez nas używane w kodzie pobierającym dane do wykresów w naszej aplikacji webowej oraz megapakiecie.
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: JPA Query Methods
Baeldung: Spring Data JPA – Adding a Method in All Repositories
Udemy: [NEW] Spring Boot 3, Spring 6 & Hibernate for Beginners — polskie napisy