Kiedy ludzie są nowi w JPA, Hibernate lub EclipseLink, często są zdezorientowani co do różnicy między nimi i którego powinni użyć w swoim projekcie. Jeśli jesteś jednym z nich, nie martw się. To o wiele łatwiejsze, niż się wydaje.
przyjrzyjmy się najpierw specyfikacji JPA.
Java Persistence API (JPA)
JPA jest skrótem oznaczającym Java Persistence API. Jest to specyfikacja, która jest częścią Java EE i definiuje API do mapowania obiektowo-relacyjnego oraz do zarządzania obiektami trwałymi. API można używać w środowiskach Java SE i Java EE.
specyfikacja jest obecnie dostępna w wersji 2.2. Dokument można pobrać pod adresem https://jcp.org/en/jsr/detail?id=338. Jar API jest dostępny pod następującymi współrzędnymi Mavena:
<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version></dependency>
JPA nie udostępnia żadnych klas implementacji. Jar interfejsu API zawiera tylko zestaw interfejsów, których można użyć do implementacji warstwy trwałości. Ale nie możesz sam używać JPA. Potrzebujesz dostawcy JPA, który implementuje specyfikację. Dostępnych jest kilka opcji. Najpopularniejsze to Hibernate i EclipseLink. Ale o tym później.
do niedawna JPA było zarządzane i rozwijane przez grupę ekspertów po procesie Java Community Process (JCP). Zmieniło się to, gdy Oracle ogłosił przeniesienie wszystkich specyfikacji Java EE do Eclipse Foundation. Jesteśmy teraz w trakcie procesu przejścia i wkrótce zostanie zdefiniowany nowy proces specyfikacji.
co jest zdefiniowane przez specyfikację JPA
Specyfikacja definiuje większość funkcji, które wyjaśniłem w samouczkach i filmach na tej stronie. Można ich używać we wszystkich zgodnych implementacjach JPA.
przyjrzyjmy się najważniejszym z nich.
Bootstrapping i podstawowe mapowania encji
zanim zaczniesz używać JPA, musisz dodać go do swojego projektu, skonfigurować jednostkę trwałości, zmapować encje do tabel bazy danych i uruchomić go. Prawdopodobnie już wiesz, jak to zrobić, i wyjaśniłem to bardzo szczegółowo w moim artykule pierwsze kroki z Hibernate.
pomińmy więc tę część i porozmawiajmy o bardziej interesujących funkcjach.
mapowanie Asocjacji
JPA umożliwia nie tylko mapowanie prostych atrybutów encji do kolumn bazy danych, ale także mapowanie asocjacji między tabelami bazy danych na atrybuty encji.
@Entitypublic class Review {...@ManyToOneprivate Book book;...}
to często sprawia, że model encji jest bardzo wygodny w użyciu, ponieważ wystarczy wywołać metodę getter na encji, aby załadować powiązane encje. W tle dostawca trwałości wykonuje wszystkie wymagane operacje na bazie danych, aby pobrać skojarzenie i zarządzać nim.
chociaż jest to wygodne w użyciu, często powoduje problemy z wydajnością. Zanim zaczniesz modelować skojarzenia między swoimi podmiotami, upewnij się, że rozumiesz wpływ typów FetchTypes JPA, aby uniknąć problemów z wyborem N + 1.
JPQL i natywne zapytania
JPA definiuje własny język zapytań, zwany JPQL. Jest podobny do SQL, ale umożliwia definiowanie zapytań w oparciu o zmapowany model domeny zamiast modelu tabeli bazy danych.
poniższy fragment kodu pokazuje proste zapytanie JPQL. Możesz zdefiniować zapytanie ad-hoc, wywołując metodę createQuery w EntityManager em. Jak widać składnia wygląda bardzo podobnie do SQL. Jeśli nie jesteś zaznajomiony z JPQL, zapoznaj się z moim przewodnikiem JPQL, w którym szczegółowo wyjaśniam jego składnię i możliwości.
TypedQuery<Book> q = em.createQuery("SELECT b FROM Book b WHERE b.id = :id", Book.class);q.setParameter("id", 1L);Book b = q.getSingleResult();
kiedy wykonujesz takie zapytanie, Twój dostawca trwałości interpretuje instrukcję JPQL i generuje dla niej zapytanie SQL. W ten sposób dostawca trwałości dostosowuje zapytanie do specyficznego dla bazy danych dialektu SQL i poprawia przenośność aplikacji.
Niestety, ogranicza cię to również do funkcji zapytań zdefiniowanych w specyfikacji lub obsługiwanych własnościowo przez Twojego dostawcę trwałości. Ten zestaw funkcji jest znacznie mniejszy niż ten oferowany przez SQL i nie zawiera żadnych zastrzeżonych funkcji bazy danych.
ale to nie znaczy, że nie można używać żadnych zaawansowanych lub złożonych zapytań z JPA. Jest zaprojektowany jako nieszczelna abstrakcja i umożliwia wykonywanie natywnych zapytań SQL. Nie są one analizowane przez dostawcę programu persistence i można korzystać ze wszystkich funkcji obsługiwanych przez bazę danych. Należy jednak pamiętać, że może to negatywnie wpłynąć na przenośność bazy danych.
wykonanie natywnego zapytania jest dość proste. Wystarczy wywołać metodę createNativeQuery zamiast metody createQuery w Menedżerze EntityManager z natywnym zapytaniem SQL.
Query q = em.createNativeQuery("SELECT * FROM book b WHERE id = :id", Book.class);q.setParameter("id", 1L);Book b = (Book) q.getSingleResult();
niestandardowe typy danych
Specyfikacja JPA definiuje mapowanie dla większości standardowych typów bez ograniczania Cię do nich. Od wersji JPA 2.1 można łatwo obsługiwać niestandardowe typy danych za pomocą programu AttributeConverter. Wystarczy zaimplementować interfejs AttributeConverter i przypisać klasę adnotacją @ Converter.
oto przykład konwertera atrybutów, który definiuje niestandardowe mapowanie dla mojego AuthorStatus enum.
@Converter(autoApply = true)public class AuthorStatusConverter implements AttributeConverter<AuthorStatus, String> {Logger log = Logger.getLogger(AuthorStatusConverter.class.getSimpleName());@Overridepublic String convertToDatabaseColumn(AuthorStatus status) {switch (status) {case NOT_PUBLISHED:logDbConversion(status, "N");return "N";case PUBLISHED:logDbConversion(status, "P");return "P";case SELF_PUBLISHED:logDbConversion(status, "S");return "S";default:throw new IllegalArgumentException("AuthorStatus not supported.");}}@Overridepublic AuthorStatus convertToEntityAttribute(String dbData) {switch (dbData) {case "N":logEntityConversion(AuthorStatus.NOT_PUBLISHED, "N");return AuthorStatus.NOT_PUBLISHED;case "P":logEntityConversion(AuthorStatus.PUBLISHED, "P");return AuthorStatus.PUBLISHED;case "S":logEntityConversion(AuthorStatus.SELF_PUBLISHED, "S");return AuthorStatus.SELF_PUBLISHED;default:throw new IllegalArgumentException("AuthorStatus not supported.");}}private void logDbConversion(AuthorStatus status, String dbData) {log.debug("Convert AuthorStatus enum to .");}private void logEntityConversion(AuthorStatus status, String dbData) {log.debug("Convert DB value to AuthorStatus enum .");}}
EclipseLink i Hibernate
jak powiedziałem wcześniej, potrzebujesz dostawcy JPA, jeśli chcesz użyć specyfikacji JPA w swoim projekcie. Implementuje interfejsy zdefiniowane w specyfikacji. Najpopularniejsze to EclipseLink i Hibernate.
jedną z zalet standardowego API dostarczanego przez JPA jest to, że wystarczy dodać jego implementację w czasie wykonywania i że można go zastąpić innym bez zmiany kodu. Standardowe API sprawia, że EclipseLink i Hibernate są wymienne.
Dlaczego więc potrzebujesz różnych implementacji?
implementacje JPA są zarządzane przez niezależne zespoły, a Ty możesz wybrać ten, który zapewnia najlepszą wydajność lub wsparcie dla Twojej aplikacji i stosu technologii. Wyróżniają się również dostarczaniem dodatkowych, niestandardowych funkcjonalności. Jest to często wykorzystywane do napędzania innowacji. Dzisiejsza popularna, zastrzeżona funkcja może być pierwszym krokiem do następnego dodatku do standardu JPA. Oczywiście korzystanie z tych zastrzeżonych funkcji znacznie utrudnia zastąpienie konkretnej implementacji JPA.
EclipseLink
EclipseLink jest implementacją referencyjną JPA i implementuje JPA w wersji 2.2. Był to jeden z pierwszych projektów, które stały się częścią EE4J.
najprostszym sposobem dodania EclipseLink do projektu jest użycie następujących współrzędnych Mavena.
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.1</version></dependency>
ciekawe funkcje zastrzeżone
oprócz funkcji zdefiniowanych przez standard JPA, EclipseLink oferuje również kilka ciekawych, zastrzeżonych funkcji, takich jak:
- Obsługa zdarzeń zmiany bazy danych
- złożone jednostki trwałości do mapowania jednostek do tabel w wielu bazach danych
- Obsługa wielu dzierżaw
Hibernate
Hibernate jest bardzo popularną implementacją specyfikacji JPA firmy Red Hat. Implementuje prawie wszystkie funkcje zdefiniowane przez JPA 2.2 i wkrótce wyda w pełni zgodną wersję.
następująca zależność Mavena dodaje Hibernate do twojego projektu.
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.1.11</version></dependency>
ciekawe funkcje zastrzeżone
podobnie jak w przypadku EclipseLink, Hibernate oferuje szereg ciekawych, zastrzeżonych funkcji, takich jak:
- Rozszerzone wsparcie dla naturalnych identyfikatorów
- ładowanie wielu podmiotów za pomocą ich klucza podstawowego
- zarządzanie znacznikami czasu tworzenia i aktualizacji
- dołączanie niepowiązanych podmiotów w zapytaniach
- wsparcie dla Multi-najmu