Spring Data Jpa

Spring Data JPA – wprowadzenie

Spring Data to jeden z najbardziej przydatnych komponentów Springa. Pozwala on w łatwy sposób wyeliminować powtarzalny kod (boiler plate). Bez niego programista musi pisać o wiele więcej linijek technicznego kodu, którego utrzymywanie wraz z rozrostem projektu może sprawiać wiele problemów. Spring data to lubiane przez wielu programistów narzędzie, ale ma ono też swoje słabe strony i nie nadaje się do każdego rodzaju projektów.

Czym jest Spring Data?

Spring Data JPA, bo o tej wersji będziemy niniejszy artykuł, jest projektem, który ma za zadanie ułatwić życie programistom, którzy w swoich projektach często wykorzystują dostęp do bazy danych przy pomocy ORMa. Eliminuje on prawie do zera potrzebę pisania kodu dostępowego, czy też zapytań do bazy danych (chociaż nie da się ich całkiem wyeliminować).

Jest to framework, który bazuje na JPA (Java Persistance Api), którego dostawcą jest domyślnie Hibernate. Jest on kolejną warstwą abstrakcji, nabudowaną na tych właśnie dwóch narzędziach.

Co to jest JPA?

Java Persistence API to specyfikacja opisująca sposób zarządzania relacyjnymi bazami danych. Powstała jako część Enterprise Java Bean 3.0 (EJB), i o ile samo EJB jest coraz mniej popularne, to JPA przyjęło się całkiem dobrze.

Na JPA składa się Api, które jest zawarte w pakiecie javax.persistence. JPQL (Java Persistence Query Language) – język zapytań, który jest trochę podobny do sqla, z tą różnicą, że operuje na obiektach, a nie na tabelach.

Jaką rolę spełnia w tym ORM?

Hibernate, bo tego ORMa domyślnie używa Spring Data, jest tutaj implementacją standardu JPA. Chociaż samego Hibernata można też używać na wiele sposobów (ma on nawet własną odmianę języka zapytań podobnego do JPQLa, który nazywa się HQL).

Hiberanate wraz z JPA daje nam warstwę abstrakcji nad bazą danych jakiej używamy. Wystarczy, że dołączymy do projektu .jara ze sterownikiem JDBC do odpowiedniej bazy danych i wszystko powinno zadziałać. I teoretycznie możemy w trakcie trwania projektu przełączyć się na dowolną inną bazę danych i cały projekt powinien działać bez problemu. W praktyce jednak zmiana silnika baz danych podczas życia projektu zdarza się bardzo rzadko. W całej karierze nigdy nie spotkałem się z taką sytuacją (co nie znaczy, że nigdy taka sytuacja nie nastąpi). Ale za to spotkałem się z sytuacją, gdzie lokalnie pracowałem na Postgresql, a produkcyjnie projekt działał na Mssql. I w tej sytuacji użycie ORMa jest bardzo przydatne, chociaż to też bardzo rzadka sytuacja.

 

Najbardziej przydatne funkcje Spring Data

Najważniejszą funkcją jest oczywiście to, że nie musisz niczego implementować, żeby wykonywać podstawowe operacje na danych. Wystarczy, że stworzysz odpowiedni interfejs, który dziedziczy po JpaRepository i masz już dostęp do podstawowych operacji takich jak findAll(), findById(ID id)save(S entity), czy deleteById(ID id).

Kolejna i bardzo przydatna rzecz to definiowanie własnych metod na podstawie konwencji nazewniczej np:

findBy<tutaj nazwa pola>(...)

findBy<tutaj nazwa pola>And<tutaj nazwa kolejnego pola>(...)

countBy<tutaj nazwa pola>(...)

existsBy<tutaj nazwa pola>(...)

streamBy<tutaj nazwa pola>(...)

itd.

 

Wystarczy, że dopiszesz taką metodę w swoim interfejsie, a spring wygeneruje Ci do niej implementację. Więcej na temat jak budować nazwy własnych metod znajdziesz w dokumentacji query-methods.

To tylko najważniejsze funkcje Spring data, więcej możesz znaleźć w dokumentacji.

 

Czy potrzebujemy dodatkowej warstwy abstrakcji?

Jak już wspomniałem, Spring Data jest kolejną warstwą abstrakcji, która jest dodana nad JPA i Hibernatem, ale jest to warstwa, której trudno uniknąć. Gdy nie korzystasz z tego narzędzia, a nadal chcesz korzystać z Hibernate i JPA, to sam musisz napisać kod dostępu do bazy danych, zapytanie JPQL i obsłużyć parametry zapytania.

Przykładowy kod, który pobiera użytkownika, wygląda mniej więcej tak:

EntityManager entityManager = emf.createEntityManager();
Query query  = entityManager.createQuery("Select u From User Where id=:id");
query.setParameter("id", 1L);
User user = query.getSingleResult();

Gdzie w Spring Data jest to wywołanie tylko jednej metody:

User user = userRepository.findById(1L);

Różnica jest ogromna i w ilości kodu i w czasie jaki jest potrzebny do napisania jednego i drugiego kodu. Także w możliwości popełnienia błędu. Im więcej kodu, tym większe ryzyko na popełnienie w nim błędu.

 

Do czego najlepiej nadaje się Spring Data?

Skoro na dostępie do bazy narosło tyle warstw, to czy potrzebujemy tak skomplikowanych narzędzi wszędzie. Oczywiście, że nie, ale teraz postaram się opisać, gdzie to narzędzie może nam się przydać.

Zarówno sam ORM , jak i Spring Data najlepiej sprawdzają się w projektach typu CRUD (Create Read Update Delete). Są to projekty zwykle stosunkowo proste, gdzie większość funkcjonalności to prosty zapis i odczyt danych do i z tabeli. A relacje pomiędzy tabelami są stosunkowo proste. Właściwie prawie każdy projekt webowy zawiera jakieś elementy CRUDa.

Dzisiaj, w zasadzie w każdym nowo rozpoczynanym projekcie webowym, wykorzystałbym te narzędzie. Zwłaszcza na początku projektu, gdzie jest dużo do zrobienia i chcemy szybko widzieć postępy prac. Odchodzi nam wtedy cały boiler plate kod potrzebny do operacji na bazie danych. Dodatkowo korzystając z Spring Data zawsze możemy skorzystać z natywnych zapytań SQL, które pozwolą nam zrealizować bardziej specyficzne zapytania do bazy danych.

Używanie Spring Data nie zamyka nam drogi do korzystania z innych podobnych narzędzi. Jeśli stwierdzisz, że w którejś części twojego projektu zajdzie potrzeba skorzystania z np. Jdbc Template, to nic nie stoi na przeszkodzie by go użyć.

 

Gdzie Spring Data nie zawsze się sprawdza?

Wszędzie tam, gdzie potrzeba dużej wydajności przy operacjach na bazie danych, Spring Data może być słabym rozwiązaniem, ale nie wynika to tylko z samego Spring Data, a z użycia ORMa. Hibernate (tak samo, jak inne ORMy) dodaje pewien narzut i trudno jest go uniknąć stosując to narzędzia. I to jest jeden z kluczowych powodów, który decyduje o tym, czy używać Spring Data i ORMa, czy nie.

Jeśli planujesz użycie Hibernate bez używania Spring Data, to raczej kiepski pomysł, ponieważ dodajesz sobie niepotrzebnie dodatkową pracę, której możesz uniknąć stosując to narzędzie.

Kolejnym istotnym powodem nieużywania Spring Data jest nieznajomość komponentów, z których jest zbudowane, czyli JPA i Hibernata. Używanie tych narzędzi do prostych przypadków jest raczej proste. Problemy zaczynają się, gdy trzeba zrobić coś bardziej skomplikowanego niż zapisanie czy odczyt pojedynczej encji.

Zrozumienie i nauczenie się tego, jak w poszczególnych przypadkach działa Hibernate jest czasochłonne. A poznanie jego wszystkich niuansów wymaga sporo czasu. Czasem lepiej zrezygnować z jakiegoś narzędzia, zamiast stosować je na siłę i stresować się w sytuacjach, kiedy coś nie działa. Pomocny tu może by mój artykuł: Trzy rzeczy, które powinieneś wiedzieć o Hibernate.

 

Podsumowanie

To tylko krótki wstęp do Spring Data. Mam nadzieję, że zachęciłem Cię do głębszego poznania tego narzędzia, a także Hibernate’a, który jest jego najważniejszą częścią. Jest jeszcze kilka ciekawych zagadnień związanych z tym narzędziem, które postaram się opisać w kolejnych artykułach.

 

Źródła:

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

https://hibernate.org/orm/documentation/5.4/

 

Mateusz Dąbrowski

Cześć jestem Mateusz, zajmuję się programowaniem już ponad 12 lat z czego ponad 8 programuję w Javie. Zapraszam Cię do lektury mojego bloga. Możesz przeczytać więcej o mnie >>TUTAJ<<

4 thoughts to “Spring Data JPA – wprowadzenie”

  1. „Jest to framework, który bazuje na JPA (Java Persistance Api), którego dostawcą jest domyślnie Hibernate.”

    Uważam to za przesadne stwierdzenie. Hibernate jest najpopularniejszą implementacją, ale nie domyślną. Np. implementacją referencyjną JPA jest EclipseLink. Np. WebSphere AS domyślnie używa OpenJPA. I tak dalej.

    „Kolejnym istotnym powodem nieużywania Spring Data jest nieznajomość komponentów, z których jest zbudowane, czyli JPA i Hibernata. ”
    „Mam nadzieję, że zachęciłem Cię do głębszego poznania tego narzędzia, a także Hibernate’a, który jest jego najważniejszą częścią.”

    Zdecdyowanie Hibernate nie jest częścią Spring Data JPA. Spring Data JPA jest warstwa abstrakcji nad JPA. To czy jako implementacja JPA będzie użyty Hibernate, EclipseLink, OpenJPA czy inna implementacja nie ma znaczenia. Zobacz sobie np. implementację SimpleJpaRepository: https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java – tam nie ma słowa o Hibernate. Wszystkie operacje są wykonywane na interfejsie EntityManager. To czy pod spodem będzie Hibernate czy coś innego – nie ma żadnego znaczenia.

    1. Domyślnie w tym sensie, gdy używasz Spring Data ze Spring Boot to masz skonfigurowanego Springa z Hibernatem. Często używam takiego skrótu myślowego (może trochę błędnie), bo w większości przypadków korzystam ze Spring Boota i wiele osób robi podobnie. Co do innych ORMów to raczej mało kto ich używa, więc nawet o nich nie wspominałem, bo trochę szkoda czasu – to moje subiektywne spojrzenie na tą sprawę.

      I tak Hibernate nie jest integralną częścią Spring Data, jest ORMem, bez którego Spring Data nie może działać. Rozpatrywanie Spring Data bez ORMa (w domyśle Hibernata) nie ma trochę sensu.

  2. Dla mnie jest to zwyczajnie dziwaczna koncepcja że programista pisze interfejs, a nie jego implementację.
    Wielokrotnie zdarzało mi się robić odwrotnie, tj. pisać implementację do gotowych interfejsów, albo też i jedno i drugie.
    Trudno mi sobie wyobrazić że gdzieś pod spodem w kodzie Springa jest kod będący implementacją do interfejsów które dopiero powstaną.

    1. Na początku oczywiście może wydawać się to dziwaczne. Ale jak już przywykniesz, to okazuje się, że jest to całkiem fajna koncepcja. I przede wszystkim oszczędzasz w ten sposób dużo czasu i nie musisz ciągle pisać takich samych metod dla wszystkich encji typu findById(). A to naprawdę robi wielką różnicę. Generalnie widzę to jako wyraz sprytu programistów, którzy kiedyś stwierdzili, po co klepać ciągle ten sam kod (tylko dla różnych encji), lepiej zrobić narzędzie, które zrobi to za nas 😉

      Takie podejście znajdziesz też w kliencie http Feign, o którym tez już pisałem.

      „Trudno mi sobie wyobrazić że gdzieś pod spodem w kodzie Springa jest kod będący implementacją do interfejsów które dopiero powstaną.”
      Każdy z nowo powstałych interfejsów musi dziedziczyć, po jakimś interfejscie Spring Data np. JpaRepository. Więc implemnentacj jest tak naprawdę dla interfejsu JpaRepository, Ty swoim interfejsem pokazujesz Spring Data dla jakiego typu będzie musiał stworzyć implementację(to tak trochę w uproszczeniu).
      Polecam także zajrzeć do klasy SimpleJpaRepository, która jest odpowiedzialna za domyślną implementację dla interfejsów w Spring Data.

Komentarze są zamknięte.