Java Persistence API (JPA) er en Java-specifikation, der bygger bro mellem relationelle databaser og objektorienteret programmering. Denne tutorial i to dele introducerer JPA og forklarer, hvordan Java-objekter modelleres som JPA-enheder, hvordan enhedsforhold defineres, og hvordan JPA'er bruges EntityManager
med arkivet mønster i dine Java-applikationer.
Bemærk, at denne vejledning bruger dvale som JPA-udbyder. De fleste begreber kan udvides til andre Java-persistensrammer.
Hvad er JPA?
Se "Hvad er JPA? Introduktion til Java Persistence API" for at lære om udviklingen af JPA og relaterede rammer, herunder EJB 3.0. og JDBC.
Objektrelationer i JPA
Relationsdatabaser har eksisteret som et middel til lagring af programdata siden 1970'erne. Mens udviklere i dag har mange alternativer til relationsdatabasen, er denne type database skalerbar og forstået og bruges stadig i vid udstrækning i små og store softwareudviklinger.
Java-objekter i en relationel databasekontekst er defineret som enheder. Enheder placeres i tabeller, hvor de optager kolonner og rækker. Programmører bruger udenlandske nøgler og deltage i tabeller at definere forholdet mellem enheder - nemlig en-til-en, en-til-mange og mange-til-mange relationer. Vi kan også bruge SQL (Structured Query Language) til at hente og interagere med data i individuelle tabeller og på tværs af flere tabeller ved hjælp af udenlandske nøglebegrænsninger. Relationsmodellen er flad, men udviklere kan skrive forespørgsler for at hente data og konstruere objekter fra disse data.
Objekt-relationer impedans uoverensstemmelse
Du er måske bekendt med udtrykket objekt-relationer impedans uoverensstemmelse, der henviser til udfordringen ved at kortlægge dataobjekter til en relationsdatabase. Denne uoverensstemmelse opstår, fordi objektorienteret design ikke er begrænset til en-til-en, en-til-mange og mange-til-mange relationer. I stedet for i objektorienteret design tænker vi på objekter, deres attributter og adfærd, og hvordan objekter forholder sig. To eksempler er indkapsling og arv:
- Hvis et objekt indeholder et andet objekt, definerer vi dette igennem indkapsling--en har en forhold.
- Hvis et objekt er en specialisering af et andet objekt, definerer vi dette igennem arv- en er en forhold.
Associering, sammenlægning, komposition, abstraktion, generalisering, realisering og afhængigheder er alle objektorienterede programmeringskoncepter, der kan være udfordrende at kortlægge til en relationel model.
ORM: Objektrelationel kortlægning
Misforholdet mellem objektorienteret design og relationel databasemodellering har ført til en klasse værktøjer, der er udviklet specielt til objektrelationskortlægning (ORM). ORM-værktøjer som dvale, EclipseLink og iBatis oversætter relationelle databasemodeller, inklusive enheder og deres forhold, til objektorienterede modeller. Mange af disse værktøjer eksisterede før JPA-specifikationen, men uden en standard var deres funktioner leverandørafhængige.
Java Persistence API (JPA) blev først frigivet som en del af EJB 3.0 i 2006 og tilbyder en standard måde at kommentere objekter på, så de kan kortlægges og lagres i en relationsdatabase. Specifikationen definerer også en fælles konstruktion til interaktion med databaser. At have en ORM-standard til Java giver konsistens til leverandørimplementeringer, samtidig med at det giver mulighed for fleksibilitet og tilføjelser. Selvom den originale JPA-specifikation finder anvendelse på relationelle databaser, har nogle leverandørimplementeringer udvidet JPA til brug sammen med NoSQL-databaser.
Udvikling af JPA
Den første udgivelse af JPA, version 1.0, blev offentliggjort i 2006 gennem Java Community Process (JCP) som Java Specification Request (JSR) 220. Version 2.0 (JSR 317) blev offentliggjort i 2009, version 2.1 (JSR 338) i 2013, og version 2.2 (en vedligeholdelsesudgivelse af JSR 338) blev offentliggjort i 2017. JPA 2.2 er valgt til inkludering og løbende udvikling i Jakarta EE.
Kom godt i gang med JPA
Java Persistence API er en specifikation og ikke en implementering: den definerer en almindelig abstraktion, som du kan bruge i din kode til at interagere med ORM-produkter. Dette afsnit gennemgår nogle af de vigtige dele af JPA-specifikationen.
Du lærer at:
- Definer enheder, felter og primære nøgler i databasen.
- Opret relationer mellem enheder i databasen.
- Arbejd med
EntityManager
og dens metoder.
Definere enheder
For at definere en enhed skal du oprette en klasse, der er kommenteret med @Enhed
kommentar. Det @Enhed
kommentar er en markørnotering, som bruges til at opdage vedvarende enheder. Hvis du f.eks. Vil oprette en bogenhed, vil du kommentere den som følger:
@Entity public class Book {...}
Som standard kortlægges denne enhed til Bestil
tabel, som bestemt af det givne klassenavn. Hvis du vil kortlægge denne enhed til en anden tabel (og eventuelt et bestemt skema), kan du bruge @Bord
kommentar til at gøre det. Sådan kan du kortlægge Bestil
klasse til et BOOKS-bord:
@Entity @Table (name = "BOOKS") offentlig klasse Bog {...}
Hvis BOOKS-tabellen var i PUBLISHING-skemaet, kan du føje skemaet til @Bord
kommentar:
@Table (name = "BOOKS", skema = "PUBLICERING")
Kortlægning af felter til kolonner
Med enheden tilknyttet en tabel, er din næste opgave at definere dens felter. Felter er defineret som medlemsvariabler i klassen, hvor navnet på hvert felt kortlægges til et kolonnenavn i tabellen. Du kan tilsidesætte denne standardkortlægning ved hjælp af @Kolonne
kommentar, som vist her:
@Entity @Table (name = "BOOKS") offentlig klasse Bog {privat strengnavn; @Column (name = "ISBN_NUMBER") privat streng isbn; ...}
I dette eksempel har vi accepteret standardkortlægningen til navn
attribut men specificerede en brugerdefineret kortlægning for isbn
attribut. Det navn
attribut vil blive kortlagt til navn kolonne, men isbn
attribut bliver kortlagt til kolonnen ISBN_NUMBER.
Det @Kolonne
kommentar giver os mulighed for at definere yderligere egenskaber for feltet / kolonnen, inklusive længde, om det er ugyldigt, om det skal være unikt, dets præcision og skala (hvis det er en decimalværdi), om det kan indsættes og opdateres osv.
Angivelse af den primære nøgle
Et af kravene til en relationsdatabasetabel er, at den skal indeholde en primærnøgle, eller en nøgle, der entydigt identificerer en bestemt række i databasen. I JPA bruger vi @Id
kommentar for at angive et felt, der skal være tabellens primære nøgle. Den primære nøgle kræves for at være en Java primitiv type, en primitiv indpakning, såsom Heltal
eller Lang
, a Snor
, a Dato
, a BigInteger
, eller a BigDecimal
.
I dette eksempel kortlægger vi id
attribut, som er en Heltal
til ID-kolonnen i BOOKS-tabellen:
@Entity @Table (name = "BOOKS") offentlig klasse Bog {@Id privat heltal id; privat strengnavn; @Column (name = "ISBN_NUMBER") privat streng isbn; ...}
Det er også muligt at kombinere @Id
kommentar med @Kolonne
kommentar for at overskrive den primære nøgles kortlægning af kolonnenavn.
Forhold mellem enheder
Nu hvor du ved, hvordan du definerer en enhed, skal vi se på, hvordan man opretter relationer mellem enheder. JPA definerer fire annoteringer for at definere enheder:
@En til en
@OneToMany
@ManyToOne
@ManyToMany
En-til-en-forhold
Det @En til en
annotering bruges til at definere en en-til-en-relation mellem to enheder. For eksempel kan du have en Bruger
enhed, der indeholder en brugers navn, e-mailadresse og adgangskode, men du vil muligvis bevare yderligere oplysninger om en bruger (såsom alder, køn og favoritfarve) i en separat Brugerprofil
enhed. Det @En til en
annotering letter nedbrydning af dine data og enheder på denne måde.
Det Bruger
klasse nedenfor har en enkelt Brugerprofil
eksempel. Det Brugerprofil
kort til en enkelt Bruger
eksempel.
@Entity offentlig klasse bruger {@Id privat heltal id; privat streng-mail; privat strengnavn; privat strengadgangskode; @OneToOne (mappedBy = "bruger") privat UserProfile-profil; ...}
@Entity offentlig klasse UserProfile {@Id privat heltal-id; privat int alder privat String køn; private streng favoritFarve; @OneToOne privat brugerbruger; ...}
JPA-udbyderen bruger Brugerprofil
's bruger
felt til kort Brugerprofil
til Bruger
. Kortlægningen er specificeret i kortlagt af
attribut i @En til en
kommentar.
En-til-mange og mange-til-en relationer
Det @OneToMany
og @ManyToOne
annoteringer letter begge sider af det samme forhold. Overvej et eksempel, hvor en Bestil
kan kun have en Forfatter
, men en Forfatter
kan have mange bøger. Det Bestil
enhed ville definere en @ManyToOne
forhold til Forfatter
og Forfatter
enhed ville definere en @OneToMany
forhold til Bestil
.
@Entity public class Book {@Id privat heltal-id; privat strengnavn; @ManyToOne @JoinColumn (name = "AUTHOR_ID") privat forfatterforfatter; ...}
@Entity public class Forfatter {@Id @GeneratedValue privat heltal-id; privat strengnavn; @OneToMany (mappedBy = "author") private Listebøger = ny ArrayList (); ...}
I dette tilfælde er Forfatter
klasse opretholder en liste over alle bøger skrevet af forfatteren og Bestil
klasse opretholder en henvisning til sin eneste forfatter. Derudover er @JoinColumn
angiver kolonnens navn i Bestil
tabel til at gemme id'et på Forfatter
.
Mange-til-mange relationer
Endelig blev @ManyToMany
annotering letter et mange-til-mange forhold mellem enheder. Her er et tilfælde, hvor en Bestil
enhed har flere Forfatter
s:
@Entity public class Book {@Id privat heltal-id; privat strengnavn; @ManyToMany @JoinTable (name = "BOOK_AUTHORS", joinColumns = @ JoinColumn (name = "BOOK_ID"), inverseJoinColumns = @ JoinColumn (name = "AUTHOR_ID")) private sæt forfattere = nyt HashSet (); ...}
@Entity public class Forfatter {@Id @GeneratedValue privat heltal id; privat strengnavn; @ManyToMany (mappedBy = "author") private Sæt bøger = nyt HashSet (); ...}
I dette eksempel opretter vi en ny tabel, BOOK_AUTHORS
med to kolonner: BOOK_ID
og AUTHOR_ID
. Bruger joinColumns
og inverseJoinColumns
attributter fortæller din JPA-ramme, hvordan man kortlægger disse klasser i et mange-til-mange forhold. Det @ManyToMany
kommentar i Forfatter
klasse henviser til feltet i Bestil
klasse, der styrer forholdet; nemlig forfattere
ejendom.
Det er en hurtig demo for et ret komplekst emne. Vi dykker længere ned i @JoinTable
og @JoinColumn
kommentarer i den næste artikel.
Arbejde med EntityManager
EntityManager
er den klasse, der udfører databaseinteraktioner i JPA. Det initialiseres via en konfigurationsfil med navnet persistence.xml
. Denne fil findes i META-INF
mappe i din CLASSPATH
, som typisk er pakket i din JAR- eller WAR-fil. Det persistence.xml
filen indeholder:
- Den navngivne "vedholdenhedsenhed", der specificerer den vedvarende ramme, du bruger, såsom Hibernate eller EclipseLink.
- En samling af egenskaber, der specificerer, hvordan du opretter forbindelse til din database, samt eventuelle tilpasninger i persistens-rammen.
- En liste over enhedsklasser i dit projekt.
Lad os se på et eksempel.
Konfiguration af EntityManager
Først opretter vi en EntityManager
bruger EntityManagerFactory
hentet fra Udholdenhed
klasse:
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory ("Bøger"); EntityManager entityManager = entityManagerFactory.createEntityManager ();
I dette tilfælde har vi oprettet en EntityManager
der er forbundet til "Bøger" vedholdenhed enhed, som vi har konfigureret i persistence.xml
fil.
Det EntityManager
klasse definerer, hvordan vores software vil interagere med databasen gennem JPA-enheder. Her er nogle af de metoder, der bruges af EntityManager
:
finde
henter en enhed med dens primære nøgle.createQuery
skaber enForespørgsel
forekomst, der kan bruges til at hente enheder fra databasen.createNamedQuery
belastninger aForespørgsel
der er defineret i en@NamedQuery
kommentar inde i en af de vedholdende enheder. Navngivne forespørgsler give en ren mekanisme til centralisering af JPA-forespørgsler i definitionen af den persistensklasse, som forespørgslen udføres på.getTransaction
definerer enEntityTransaction
at bruge i dine databaseinteraktioner. Ligesom databasetransaktioner starter du typisk transaktionen, udfører dine operationer og derefter enten begår eller tilbagefører din transaktion. DetgetTransaction ()
metoden giver dig adgang til denne adfærd på niveauet forEntityManager
, snarere end databasen.fusionere()
tilføjer en enhed til persistens-konteksten, så når transaktionen begås, forbliver enheden i databasen. Ved brugfusionere()
, genstande administreres ikke.vedvarer
tilføjer en enhed til persistens-konteksten, så når transaktionen begås, forbliver enheden i databasen. Ved brugvedvarer ()
, objekter administreres.Opdater
opdaterer tilstanden for den aktuelle enhed fra databasen.Flush
synkroniserer tilstanden af persistens-konteksten med databasen.
Du skal ikke bekymre dig om at integrere alle disse metoder på én gang. Du lærer dem at kende ved at arbejde direkte med EntityManager
, som vi gør mere i næste afsnit.