ca specificație, API-ul Java Persistence este preocupat de persistență, ceea ce înseamnă vag orice mecanism prin care obiectele Java supraviețuiesc procesului de aplicare care le-a creat. Nu toate obiectele Java trebuie să fie persistat, dar cele mai multe aplicații persistă obiecte cheie de afaceri. Specificația JPA vă permite să definiți ce obiecte ar trebui să fie persistat, și modul în care aceste obiecte ar trebui să fie persistat în aplicațiile Java.
în sine, JPA nu este un instrument sau cadru; mai degrabă, definește un set de concepte care pot fi implementate de orice instrument sau cadru. În timp ce modelul de mapare a obiectelor relaționale (ORM) al JPA s-a bazat inițial pe hibernare, acesta a evoluat de atunci. De asemenea, în timp ce JPA a fost inițial destinat utilizării cu baze de date relaționale/SQL, unele implementări JPA au fost extinse pentru utilizare cu magazinele de date NoSQL. Un cadru popular care acceptă JPA cu NoSQL este EclipseLink, implementarea de referință pentru JPA 2.2.
JPA și Hibernate
Din cauza istoriei lor interconectate, Hibernate și JPA sunt frecvent combinate. Cu toate acestea, la fel ca specificația Java Servlet, JPA a generat multe instrumente și cadre compatibile; Hibernate este doar unul dintre ele.dezvoltat de Gavin King și lansat la începutul anului 2002, Hibernate este o bibliotecă ORM pentru Java. King a dezvoltat Hibernate ca o alternativă la fasolea entității pentru persistență. Cadrul a fost atât de popular și atât de necesar la acea vreme, încât multe dintre ideile sale au fost adoptate și codificate în prima specificație JPA.
astăzi, Hibernate ORM este una dintre cele mai mature implementări JPA și încă o opțiune populară pentru ORM în Java. Hibernare ORM 5.3.8 (versiunea curentă din această scriere) implementează JPA 2.2. În plus, familia de instrumente Hibernate s-a extins pentru a include instrumente populare precum Hibernate Search, Hibernate Validator și Hibernate OGM, care acceptă persistența modelului de domeniu pentru NoSQL.
ce este Java ORM?
în timp ce diferă în execuție, fiecare implementare JPA oferă un fel de strat ORM. Pentru a înțelege instrumentele compatibile JPA și JPA, trebuie să aveți o bună înțelegere a ORM.
maparea relațională a obiectelor este o sarcină-una pe care dezvoltatorii au motive întemeiate să evite să o facă manual. Un cadru precum Hibernate ORM sau EclipseLink codifică acea sarcină într-o bibliotecă sau cadru, un strat ORM. Ca parte a arhitecturii aplicației, stratul ORM este responsabil pentru gestionarea conversiei obiectelor software pentru a interacționa cu tabelele și coloanele dintr-o bază de date relațională. În Java, stratul ORM convertește clasele și obiectele Java astfel încât acestea să poată fi stocate și gestionate într-o bază de date relațională.
în mod implicit, numele obiectului care persistă devine numele tabelului, iar câmpurile devin coloane. Odată ce tabelul este configurat, fiecare rând de tabel corespunde unui obiect din aplicație. Maparea obiectelor este configurabilă, dar valorile implicite tind să funcționeze bine.
Figura 1 ilustrează rolul JPA și al stratului ORM în dezvoltarea aplicațiilor.
Configurarea stratului Orm Java
când configurați un nou proiect pentru a utiliza JPA, va trebui să configurați magazinul de date și furnizorul JPA. Veți configura un conector datastore pentru a vă conecta la baza de date aleasă (SQL sau NoSQL). De asemenea, veți include și configura furnizorul JPA, care este un cadru precum Hibernate sau EclipseLink. În timp ce puteți configura JPA manual, mulți dezvoltatori aleg să utilizeze suportul out-of-the-box al Spring. Consultați „Instalare și configurare JPA” de mai jos pentru o demonstrație a instalării și configurării JPA manuale și bazate pe primăvară.
persistența datelor în Java
Din perspectiva programării, stratul ORM este un strat adaptor: se adaptează limbajul graficelor obiect la limba SQL și tabele relaționale. Stratul ORM permite dezvoltatorilor orientați pe obiecte să construiască software care persistă date fără a părăsi vreodată paradigma orientată pe obiecte.
când utilizați JPA, creați o hartă de la depozitul de date la obiectele modelului de date al aplicației. În loc să definiți modul în care obiectele sunt salvate și preluate, definiți maparea între obiecte și baza de date, apoi invocați JPA pentru a le persista. Dacă utilizați o bază de date relațională, o mare parte din conexiunea reală dintre codul aplicației și baza de date va fi apoi gestionată de JDBC, API-ul Java Database Connectivity.
ca spec, JPA oferă adnotări de metadate, pe care le utilizați pentru a defini maparea între obiecte și baza de date. Fiecare implementare JPA oferă propriul motor pentru adnotările JPA. Specificațiile JPA oferă, de asemenea,PersistanceManager
sauEntityManager
, care sunt punctele cheie de contact cu sistemul JPA (în care codul logic de afaceri spune sistemului ce să facă cu obiectele mapate).
pentru a face toate acestea mai concrete, luați în considerare listarea 1, care este o clasă de date simplă pentru modelarea unui muzician.
Lista 1. O clasă de date simplu în Java
Musician
clasa în listarea 1 este folosit pentru a stoca date. Poate conține date primitive, cum ar fi câmpul de nume. De asemenea, poate deține relații cu alte clase, cum ar fi mainInstrument
și performances
.
Musician
motivul existenței este de a conține date. Acest tip de clasă este uneori cunoscut sub numele de DTO sau obiect de transfer de date. DTOs sunt o caracteristică comună a dezvoltării de software. Deși dețin multe tipuri de date, ele nu conțin nicio logică de afaceri. Persistența obiectelor de date este o provocare omniprezentă în dezvoltarea de software.
persistența datelor cu JDBC
o modalitate de a salva o instanță a claseiMusician
într-o bază de date relațională ar fi utilizarea bibliotecii JDBC. JDBC este un strat de abstractizare care permite unei aplicații să emită comenzi SQL fără să se gândească la implementarea bazei de date subiacente.
listarea 2 arată cum ai putea persistaMusician
clasa folosind JDBC.
Lista 2. JDBC introducerea unei înregistrări
codul din listarea 2 este destul de auto-documentare. ObiectulgeorgeHarrison
ar putea veni de oriunde (trimitere front-end, serviciu extern etc.), și are câmpurile ID și nume setate. Câmpurile de pe obiect sunt apoi utilizate pentru a furniza valorile unei instrucțiuni SQL insert
. (Clasa PreparedStatement
face parte din JDBC, oferind o modalitate de a aplica în siguranță valori unei interogări SQL.)
în timp ce JDBC permite controlul care vine cu configurația manuală, este greoaie în comparație cu JPA. Pentru a modifica baza de date, trebuie mai întâi să creați o interogare SQL care mapează de la obiectul Java la tabelele dintr-o bază de date relațională. Apoi trebuie să modificați SQL ori de câte ori o schimbare de semnătură obiect. Cu JDBC, menținerea SQL devine o sarcină în sine.
persistența datelor cu JPA
acum luați în considerare listarea 3, unde persistămMusician
clasa folosind JPA.
Lista 3. Persistând George Harrison cu JPA
Musician georgeHarrison = new Musician(0, "George Harrison");musicianManager.save(georgeHarrison);
listarea 3 înlocuiește manualul SQL din listarea 2 cu o singură linie,session.save()
, care instruiește JPA să persiste obiectul. De atunci, conversia SQL este gestionată de cadru, deci nu trebuie să părăsiți niciodată paradigma orientată pe obiecte.
adnotări de metadate în JPA
magia din listarea 3 este rezultatul unei configurații, care este creată folosind adnotările JPA. Dezvoltatorii folosesc adnotări pentru a informa JPA ce obiecte ar trebui să fie persistate și cum ar trebui să fie persistate.
listarea 4 aratăMusician
clasa cu o singură adnotare JPA.
Lista 4. Adnotarea entității JPA
@Entitypublic class Musician { // ..class body}
obiectele persistente sunt uneori numite entități. Atașarea@Entity
la o clasă precumMusician
informează JPA că această clasă și obiectele sale ar trebui să fie persistate.
Configurarea JPA
la fel ca majoritatea cadrelor moderne, JPA cuprinde codificarea prin convenție (cunoscută și sub numele de convenție peste configurare), în care cadrul oferă o configurație implicită bazată pe cele mai bune practici din industrie. Ca un exemplu, o clasă numită Musician
ar fi mapată implicit la un tabel de baze de date numit muzician.
configurația convențională este un timesaver și, în multe cazuri, funcționează suficient de bine. De asemenea, este posibil să vă personalizați configurația JPA. De exemplu, puteți utiliza adnotarea JPA @Table
pentru a specifica tabelul în care ar trebui stocată clasa Musician
.
Lista 5. Adnotarea @Table a JPA
@Entity@Table(name="musician")public class Musician { // ..class body}
listarea 5 îi spune JPA să persiste entitatea (Musician
clasă) lamusician
tabel.
cheie primară
în JPA, cheia primară este câmpul utilizat pentru a identifica în mod unic fiecare obiect din Baza de date. Cheia primară este utilă pentru corelarea și relaționarea obiectelor cu alte entități. Ori de câte ori stocați un obiect într-un tabel, veți specifica și câmpul de utilizat ca cheie primară.
în lista 6, spunem JPA ce câmp să folosească caMusician
cheie primară.
lista 6. Specificarea cheii primare
@Entitypublic class Musician { @Id private Long id;
în acest caz, am folosit adnotarea JPA@Id
pentru a specifica câmpulid
caMusician
. În mod implicit, această configurație presupune cheia primară va fi setat de baza de date-de exemplu, atunci când câmpul este setat la auto-increment pe masă.
JPA acceptă alte strategii pentru generarea cheii primare a unui obiect. De asemenea, are adnotări pentru schimbarea numelor de câmpuri individuale. În general, JPA este suficient de flexibil pentru a se adapta la orice mapare de persistență de care ați putea avea nevoie.
operații brute
după ce ați mapat o clasă la un tabel de baze de date și ați stabilit cheia primară a acesteia, aveți tot ce aveți nevoie pentru a crea, prelua, șterge și actualiza acea clasă în baza de date. Apelarea session.save()
va crea sau actualiza clasa specificată, în funcție de faptul dacă câmpul cheie primară este nul sau se aplică entității existente en. Apelarea entityManager.remove()
va șterge clasa specificată.
relații de entitate în JPA
simpla persistență a unui obiect cu un câmp primitiv este doar jumătate din ecuație. JPA are, de asemenea, capacitatea de a gestiona entitățile în raport unul cu celălalt. Patru tipuri de relații entitate sunt posibile în ambele tabele și obiecte:
- unu-la-mulți
- mulți-la-unu
- mulți-La-mulți
- unu-la-unu
fiecare tip de relație descrie modul în care o entitate se raportează la alte entități. De exemplu, Musician
entitatea ar putea avea o relație unu-la-mulți cu Performance
, o entitate reprezentată de o colecție precum List
sau Set
.
dacăMusician
a inclus unBand
, relația dintre aceste entități ar putea fi multi-la-unu, implicând colectarea deMusician
s pe un singurBand
clasă. (Presupunând că fiecare muzician cântă doar într-o singură trupă.)
dacăMusician
a inclus unBandMates
câmp, care ar putea reprezenta o relație mulți-La-mulți cu alteMusician
entități.
în cele din urmă,Musician
ar putea avea o relație unu-la-unu cu oQuote
entitate, folosit pentru a reprezenta un citat celebru:Quote famousQuote = new Quote()
.
definirea tipurilor de relații
JPA are adnotări pentru fiecare dintre tipurile sale de mapare a relațiilor. Listarea 7 arată cum puteți adnota relația unu-la-mulți dintre Musician
și Performance
s.
listarea 7. Adnotarea unei relații unu-la-mulți
un lucru de observat este că @JoinColumn
spune JPA ce coloană din tabelul de performanță se va mapa la Musician
entitate. Fiecare performanță va fi asociată cu un singur Musician
, care este urmărit de această coloană. Când JPA Încarcă un Musician
sau unPerformance
în baza de date, va folosi aceste informații pentru a reconstitui graficul obiect.
preluarea strategiilor în JPA
pe lângă faptul că știți unde să plasați entitățile conexe în baza de date, JPA trebuie să știe cum doriți să le încărcați. Preluarea strategii spune JPA cum să încărcați entități conexe. La încărcarea și salvarea obiectelor, un cadru JPA trebuie să ofere posibilitatea de a finetune modul în care sunt manipulate graficele obiectelor. De exemplu, dacăMusician
clasa are un bandMate
câmp (așa cum se arată în lista 7), încărcare george
ar putea provoca întreaga masă muzician pentru a fi încărcate din Baza de date!
ceea ce este necesar este abilitatea de a defini încărcarea leneșă a entităților conexe–recunoscând, desigur, că relațiile din JPA pot fi dornice sau leneșe. Puteți utiliza adnotări pentru a vă personaliza strategiile de preluare, dar configurația implicită a JPA funcționează adesea din cutie, fără modificări:
- unu-la-mulți: leneș
- mulți-la-unu: dornici
- mulți-La-mulți: leneși
- unu-la-unu: dornici
-
instalare și configurare JPA
vom încheia cu o scurtă privire la instalarea și configurarea JPA pentru aplicațiile Java. Pentru această demonstrație voi folosi EclipseLink, implementarea de referință JPA.
modul comun de a instala JPA este de a include un furnizor JPA în proiectul dumneavoastră. Listarea 8 arată cum ați include EclipseLink ca dependență în fișierul Maven
pom.xml
.lista 8. Includeți EclipseLink ca dependență Maven
org.eclipse.persistenceeclipselink2.5.0-RC1
De asemenea, va trebui să includeți driverul pentru baza dvs. de date, așa cum se arată în lista 9.
lista 9. Dependență Maven pentru un conector MySql
mysqlmysql-connector-java5.1.32
apoi, va trebui să spuneți sistemului despre baza de date și furnizorul dvs. Acest lucru se face în fișierul
persistence.xml
, așa cum se arată în lista 10.Lista 10. Persistență.xml
există și alte modalități de a furniza aceste informații sistemului, inclusiv programatic. Vă recomandăm să utilizați fișierul
persistence.xml
deoarece stocarea dependențelor în acest fel face foarte ușoară actualizarea aplicației fără a modifica codul.configurarea arcului pentru JPA
utilizarea arcului va ușura foarte mult integrarea JPA în aplicația dvs. De exemplu, plasarea
@SpringBootApplication
adnotarea în antetul aplicației instruiește Spring să scaneze automat clasele și să injectezeEntityManager
după cum este necesar, pe baza configurației specificate.listarea 11 arată dependențele de inclus dacă doriți suportul JPA Spring pentru aplicația dvs.
lista 11. Adăugarea suportului JPA de primăvară în Maven
concluzie
fiecare aplicație care se ocupă de o bază de date ar trebui să definească un strat de aplicație al cărui unic scop este izolarea codului de persistență. După cum ați văzut în acest articol, API-ul Java Persistence introduce o serie de capabilități și suport pentru persistența obiectelor Java. Este posibil ca aplicațiile Simple să nu necesite toate capacitățile JPA și, în unele cazuri, este posibil ca cheltuielile generale de configurare a cadrului să nu fie meritate. Cu toate acestea, pe măsură ce o aplicație crește, structura și încapsularea JPA își câștigă cu adevărat păstrarea. Utilizarea JPA păstrează codul obiect simplu și oferă un cadru convențional pentru accesarea datelor în aplicațiile Java.
Aflați mai multe despre API-ul Java Persistence și tehnologiile conexe
- ce este JDBC? Introducere în conectivitatea bazei de date Java: cunoașteți API-ul Java de nivel scăzut pentru conectarea la o bază de date, emiterea de interogări SQL și multe altele.
- persistența Java cu JPA și Hibernate, Partea 1: entități și Relații: începeți modelarea entităților și relațiilor cu Java 8 și Hibernate ORM.
- persistența Java cu JPA și Hibernare, Partea 2: Hands-on practică modelarea multe-la-multe relații și relații de moștenire în Java 8 și Hibernate ORM.
- implementarea comportamentului dependent de stat: o introducere clasică a modelului de stat și a dependenței de stat în Java.
- Încărcare dornică / leneșă în hibernare: cum se aplică încărcarea dornică și leneșă în hibernare.
- JPA 2.2 aduce unele modificări foarte anticipate: o prezentare generală a actualizărilor de specificații în JPA 2.2, inclusiv îmbunătățiri la CDI, o mai bună aliniere cu data și ora API, și suport pentru
@Repeatable
adnotări. - ar trebui să utilizați JPA pentru următorul proiect?: Întrebări cheie care vă pot ajuta să decideți.