Wprowadzenie
W tym poradniku będziemy omawiać Hibernate i Java Persistence API (JPA) – z naciskiem na różnice między nimi.
Zaczniemy od zbadania czym jest JPA, jak jest używane i jakie są podstawowe koncepcje stojące za nim.
Następnie przyjrzymy się, jak Hibernate i EclipseLink pasują do tego obrazu.
Object-Relational Mapping
Zanim zagłębimy się w JPA, ważne jest, aby zrozumieć koncepcję Object-Relational Mapping – znaną również jako ORM.
Object-relational mapping jest po prostu procesem przechowywania dowolnego obiektu Java bezpośrednio do tabeli bazy danych. Zazwyczaj nazwa obiektu staje się nazwą tabeli, a każde pole w tym obiekcie staje się kolumną. Po skonfigurowaniu tabeli każdy wiersz odpowiada rekordowi w aplikacji.
Wprowadzenie do JPA
Java Persistence API, lub JPA, jest specyfikacją, która definiuje zarządzanie relacyjnymi danymi w aplikacji Java. API odwzorowuje zestaw pojęć, które określają, które obiekty w aplikacji powinny być utrzymywane i jak powinny być utrzymywane.
Ważne jest, aby zauważyć, że JPA jest tylko specyfikacją i że potrzebuje implementacji, aby działać – ale więcej na ten temat później.
Teraz omówmy niektóre z podstawowych pojęć JPA, które musi obejmować implementacja.
3.1. Entity
Klasa javax.persistence.Entity definiuje, które obiekty powinny być persystowane do bazy danych. Dla każdej persystowanej encji JPA tworzy nową tabelę w ramach wybranej bazy danych.
Dodatkowo, wszystkie wybrane encje powinny definiować klucz główny oznaczony adnotacją @Id. Wraz z adnotacją @GeneratedValue definiujemy, że klucz główny powinien być automatycznie generowany podczas persystencji rekordu do bazy danych.
Przyjrzyjrzyjmy się szybkiemu przykładowi encji opisanej przez JPA.
@Entitypublic class Car { @GeneratedValue @Id public long id; // getters and setters}
Pamiętajmy, że obecnie nie będzie to miało żadnego wpływu na aplikację – JPA nie dostarcza żadnego kodu implementacyjnego.
3.2. Trwałość pól
Kolejną podstawową koncepcją JPA jest trwałość pól. Kiedy obiekt w Javie jest zdefiniowany jako encja, wszystkie pola w nim zawarte są automatycznie przechowywane jako różne kolumny w tabeli encji.
Jeśli istnieje pole w obrębie przechowywanego obiektu, którego nie chcemy przechowywać w bazie danych, możemy zadeklarować pole jako przejściowe za pomocą adnotacji @Transient.
3.3. Relacje
Następnie, JPA określa, jak powinniśmy zarządzać relacjami pomiędzy różnymi tabelami bazy danych w naszej aplikacji. Jak już widzieliśmy, JPA obsługuje to za pomocą adnotacji. Istnieją cztery adnotacje relacji, o których musimy pamiętać:
- @OneToOne
- @OneToMany
- @ManyToOne
- @ManyToMany
Przyjrzyjmy się, jak to działa:
@Entitypublic class SteeringWheel { @OneToOne private Car car // getters and setters}
W naszym powyższym przykładzie, klasa SteeringWheel opisuje relację jeden do jednego z naszą klasą Car z wcześniejszego przykładu.
3.4. Entity Manager
Na koniec, klasa javax.persistence.EntityManager określa operacje do i z bazy danych. EntityManager zawiera typowe operacje tworzenia, odczytu, aktualizacji i usuwania (CRUD), które są przechowywane w bazie danych.
Wdrożenia JPA
Mając specyfikację JPA określającą, jak i co powinniśmy przechowywać, musimy teraz wybrać dostawcę implementacji, który dostarczy niezbędny kod. Bez takiego dostawcy, musielibyśmy zaimplementować wszystkie odpowiednie klasy, aby być w zgodzie z JPA, a to wymaga dużo pracy!
Jest wiele dostawców do wyboru, a każdy z nich ma swoje wady i zalety. Podejmując decyzję, którego z nich użyć, powinniśmy rozważyć kilka z następujących punktów:
- Dojrzałość projektu – jak długo dostawca istnieje i jak dobrze jest udokumentowany?
- Podprojekty – czy dostawca ma jakieś przydatne podprojekty dla naszej nowej aplikacji?
- Wsparcie społeczności – czy jest ktoś, kto nam pomoże, gdy trafimy na krytyczny błąd?
- Benchmarking – jak wydajna jest implementacja?
Chociaż nie będziemy się zagłębiać w benchmarkowanie różnych dostawców JPA, JPA Performance Benchmark (JPAB) zawiera cenny wgląd w tę kwestię.
With that out of the way, let’s take a brief look at some of the top providers of JPA.
Hibernate
At its core, Hibernate is an object-relational mapping tool that provides an implementation of JPA. Hibernate jest jedną z najbardziej dojrzałych implementacji JPA, z ogromną społecznością wspierającą projekt.
Implementuje wszystkie klasy javax.persistence, którym przyglądaliśmy się wcześniej w artykule, jak również zapewnia funkcjonalność wykraczającą poza JPA – narzędzia Hibernate, walidację i wyszukiwanie. Chociaż te API specyficzne dla Hibernate mogą być użyteczne, nie są one potrzebne w aplikacjach, które wymagają tylko podstawowej funkcjonalności JPA.
Przyjrzyjrzyjmy się szybko temu, co Hibernate oferuje z adnotacją @Entity.
Podczas gdy spełnia kontrakt JPA, @org.hibernate.annotations.Entity dodaje dodatkowe metadane, które wykraczają poza specyfikację JPA. Pozwala to na precyzyjne dostrojenie trwałości encji. Dla przykładu, przyjrzyjmy się kilku adnotacjom oferowanym przez Hibernate, które rozszerzają funkcjonalność @Entity:
- @Table – pozwala nam określić nazwę tabeli utworzonej dla encji
- @BatchSize – określa rozmiar partii podczas pobierania encji z tabeli
Warto również zwrócić uwagę na kilka dodatkowych funkcji, których JPA nie określa, a które mogą okazać się przydatne w większych aplikacjach:
- Dostosowywalne instrukcje CRUD z adnotacjami @SQLInsert, @SQLUpate i @SQLDelete
- Wsparcie dla miękkiego usuwania
- Immutowalne encje z adnotacją @Immutable
Dla głębszego zanurzenia się w Hibernate i persystencji w Javie – przejdź do naszej serii tutoriali na temat persystencji w Spring.
EclipseLink
EclipseLink, zbudowany przez Eclipse Foundation, dostarcza otwartą implementację JPA. Dodatkowo, EclipseLink wspiera wiele innych standardów persystencji, takich jak Java Architecture for XML Binding (JAXB).
Po prostu, zamiast utrzymywać obiekt w wierszu bazy danych, JAXB mapuje go do reprezentacji XML.
Następnie, porównując tę samą implementację adnotacji @Entity, widzimy, że EclipseLink oferuje ponownie różne rozszerzenia. Podczas gdy nie ma adnotacji dla @BatchSize, jak widzieliśmy wcześniej, EclipseLink oferuje inne opcje, których Hibernate nie oferuje.
Na przykład:
- @ReadOnly – określa, że encja, która ma być przechowywana jest tylko do odczytu
- @Struct – definiuje klasę do mapowania do bazy danych typu 'struct’
Aby przeczytać więcej o tym, co EclipseLink ma do zaoferowania, przejdź do naszego przewodnika po EclipseLink ze Springiem.
Zakończenie
W tym artykule przyjrzeliśmy się Java Persistence API, czyli JPA.
Na koniec zbadaliśmy, czym różni się od Hibernate i EclipseLink.