când oamenii sunt noi la JPA, Hibernate sau EclipseLink, ei sunt adesea confuzi cu privire la diferența dintre ei și pe care ar trebui să o folosească în proiectul lor. Dacă sunteți unul dintre ei, nu vă faceți griji. Este mult mai ușor decât pare.
Să aruncăm o privire mai întâi la specificația JPA.
java persistența API (JPA)
JPA este o abreviere care vine de la Java persistența API. Este o specificație care face parte din Java EE și definește un API pentru mapările relaționale obiect și pentru gestionarea obiectelor persistente. Puteți utiliza acest API în mediile Java SE și Java EE.
specificația este disponibilă în prezent în versiunea 2.2. Puteți descărca documentul la https://jcp.org/en/jsr/detail?id=338. Jar API este disponibil la următoarele coordonate Maven:
<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version></dependency>
JPA în sine nu oferă clase de implementare. API jar conține doar un set de interfețe pe care le puteți utiliza pentru a implementa stratul de persistență. Dar nu poți folosi JPA pe cont propriu. Aveți nevoie de un furnizor JPA care pune în aplicare CAIETUL DE SARCINI. Există mai multe opțiuni disponibile. Cele mai populare sunt Hibernate și EclipseLink. Dar mai multe despre asta mai târziu.
până de curând, JPA a fost gestionat și dezvoltat de un grup de experți în urma procesului comunitar Java (JCP). Acest lucru s-a schimbat atunci când Oracle a anunțat transferul tuturor specificațiilor Java EE către Fundația Eclipse. Suntem acum în mijlocul procesului de tranziție și un nou proces de specificație va fi definit în curând.
ce este definit de specificația JPA
specificația definește majoritatea caracteristicilor pe care le-am explicat în tutorialele și videoclipurile de pe acest site. Le puteți utiliza cu toate implementările JPA conforme.
Să aruncăm o privire la unele dintre cele mai importante.
bootstrapping și mapări de entități de bază
înainte de a putea începe să utilizați JPA, trebuie să îl adăugați la proiectul dvs., să configurați o unitate de persistență, să mapați entitățile la tabelele bazei de date și să îl bootstrap. Probabil știți deja cum să faceți asta și am explicat-o în detaliu în articolul meu Noțiuni de bază cu hibernare.
deci, să omitem această parte aici și să vorbim despre caracteristicile mai interesante.
asocieri de mapare
JPA nu numai că vă permite să mapați atributele entității simple la coloanele bazei de date, dar vă permite, de asemenea, să mapați asocierile dintre tabelele bazei de date la atributele entității.
@Entitypublic class Review {...@ManyToOneprivate Book book;...}
acest lucru face ca modelul entității dvs. să fie foarte confortabil de utilizat, deoarece trebuie doar să apelați o metodă getter pe o entitate pentru a încărca entitățile asociate. În fundal, furnizorul de persistență efectuează toate operațiunile de bază de date necesare pentru a prelua și gestiona asocierea.
la fel de confortabil de utilizat ca acest lucru ar putea fi, aceste caracteristici cauzează adesea probleme de performanță. Înainte de a începe să modelați asocierile dintre entitățile dvs., asigurați-vă că înțelegeți efectul FetchTypes JPA pentru a evita problemele selectate n+1.
JPQL și interogări Native
JPA definește propriul limbaj de interogare, numit JPQL. Este similar cu SQL, dar vă permite să definiți interogări bazate pe modelul de domeniu mapat în loc de modelul tabelului bazei de date.
următorul fragment de cod arată o interogare JPQL simplă. Puteți defini o interogare ad-hoc apelând metoda createQuery pe em EntityManager. După cum puteți vedea, sintaxa arată foarte asemănătoare cu SQL. Dacă nu sunteți familiarizați cu JPQL, vă rugăm să aruncați o privire la ghidul meu JPQL în care explic sintaxa și capacitățile sale în detalii minunate.
TypedQuery<Book> q = em.createQuery("SELECT b FROM Book b WHERE b.id = :id", Book.class);q.setParameter("id", 1L);Book b = q.getSingleResult();
când executați o astfel de interogare, furnizorul dvs. de persistență interpretează instrucțiunea JPQL și generează o interogare SQL pentru aceasta. Procedând astfel, furnizorul de persistență adaptează interogarea la dialectul SQL specific bazei de date și îmbunătățește portabilitatea aplicației.
Din păcate, acest lucru vă limitează și la caracteristicile de interogare definite de specificație sau suportate în mod proprietar de furnizorul dvs. de persistență. Acest set de caracteristici este semnificativ mai mic decât cel oferit de SQL și nu include caracteristici ale bazei de date proprietare.
dar asta nu înseamnă că nu puteți utiliza interogări avansate sau complexe cu JPA. Este conceput ca o abstracție neetanșe și vă permite să execute interogări SQL native. Acestea nu sunt analizate de furnizorul dvs. de persistență și puteți utiliza toate funcțiile acceptate de baza de date. Dar vă rugăm să fiți conștienți de faptul că acest lucru ar putea afecta negativ portabilitatea bazei de date.
executarea unei interogări native este destul de simplă. Trebuie doar să apelați metoda createNativeQuery în loc de metoda createQuery pe EntityManager cu o interogare SQL nativă.
Query q = em.createNativeQuery("SELECT * FROM book b WHERE id = :id", Book.class);q.setParameter("id", 1L);Book b = (Book) q.getSingleResult();
tipuri de date personalizate
specificația JPA definește maparea pentru majoritatea tipurilor standard fără a vă limita la ele. Începând cu JPA 2.1, puteți suporta cu ușurință tipuri de date personalizate cu un AttributeConverter. Trebuie doar să implementați interfața AttributeConverter și să adnotați clasa cu o adnotare @Converter.
Iată un exemplu de convertor de atribute care definește o mapare personalizată pentru my 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 Hibernare
așa cum am spus mai înainte, aveți nevoie de un furnizor JPA, dacă doriți să utilizați specificația JPA în proiectul dumneavoastră. Acesta pune în aplicare interfețele definite de caietul de sarcini. Cele mai populare sunt EclipseLink și Hibernate.
un avantaj al API-ului standardizat furnizat de JPA este că trebuie doar să adăugați implementarea acestuia în timpul rulării și că îl puteți înlocui cu unul diferit fără a schimba niciun cod. API-ul standardizat face EclipseLink și Hibernate interschimbabile.
deci, de ce aveți nevoie de implementări diferite?implementările JPA sunt gestionate de echipe independente și o puteți alege pe cea care oferă cea mai bună performanță sau suport pentru aplicația și stiva de tehnologie. De asemenea, se diferențiază prin furnizarea de funcționalități suplimentare, non-standard. Acest lucru este adesea folosit pentru a stimula inovația. Caracteristica populară de astăzi, proprietară, ar putea fi primul pas către următoarea adăugare la standardul JPA. Folosind oricare dintre aceste caracteristici de proprietate, evident, face mult mai greu pentru a înlocui o implementare specifică JPA.
EclipseLink
EclipseLink este implementarea de referință a JPA și implementează versiunea JPA 2.2. A fost unul dintre primele proiecte care au devenit parte a EE4J.
cel mai simplu mod de a adăuga EclipseLink la proiectul dvs. este să utilizați următoarele coordonate Maven.
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.1</version></dependency>
caracteristici de proprietate interesante
în plus față de caracteristicile definite de standardul JPA, EclipseLink oferă, de asemenea, mai multe caracteristici interesante, de proprietate, cum ar fi:
- gestionarea evenimentelor de schimbare a bazei de date
- unități de persistență compozite pentru a mapa entitățile la tabele în mai multe baze de date
- suport pentru multi-închiriere
Hibernate
Hibernate este implementarea foarte populară a specificației JPA a Red Hat. Acesta pune în aplicare aproape toate caracteristicile definite de JPA 2.2 și va lansa o versiune pe deplin compatibil în curând.
următoarea dependență Maven adaugă hibernare la proiectul dumneavoastră.
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.1.11</version></dependency>
caracteristici proprietare interesante
Similar cu EclipseLink, Hibernate oferă o grămadă de caracteristici interesante, proprietare, cum ar fi:
- suport extins pentru ID-uri naturale
- încărcarea mai multor entități prin cheia lor primară
- gestionarea creării și actualizării marcajelor de timp
- alăturarea entităților neasociate în interogări
- suport pentru multi-închiriere