Programmering

Java-utholdenhet med JPA og Hibernate, del 1: enheter og relasjoner

Java Persistence API (JPA) er en Java-spesifikasjon som bygger bro mellom relasjonsdatabaser og objektorientert programmering. Denne todelte opplæringen introduserer JPA og forklarer hvordan Java-objekter er modellert som JPA-enheter, hvordan enhetsforhold er definert, og hvordan du bruker JPAs EntityManager med lagringsmønsteret i Java-applikasjonene dine.

Merk at denne veiledningen bruker dvalemodus som JPA-leverandør. De fleste konsepter kan utvides til andre Java-utholdenhetsrammer.

Hva er JPA?

Se "Hva er JPA? Introduksjon til Java Persistence API" for å lære om utviklingen av JPA og relaterte rammer, inkludert EJB 3.0. og JDBC.

Objektrelasjoner i JPA

Relasjonsdatabaser har eksistert som et middel for lagring av programdata siden 1970-tallet. Mens utviklere i dag har mange alternativer til relasjonsdatabasen, er denne typen databaser skalerbar og godt forstått, og brukes fortsatt mye i små og store programvareutviklinger.

Java-objekter i en relasjonell databasekontekst er definert som enheter. Enheter plasseres i tabeller der de opptar kolonner og rader. Programmører bruker utenlandske nøkler og bli med på bord å definere forholdet mellom enheter - nemlig en-til-en, en-til-mange og mange-til-mange relasjoner. Vi kan også bruke SQL (Structured Query Language) for å hente og samhandle med data i individuelle tabeller og på tvers av flere tabeller ved hjelp av begrensninger for utenlandske nøkler. Relasjonsmodellen er flat, men utviklere kan skrive spørsmål for å hente data og konstruere objekter fra disse dataene.

Objekt-relasjoner impedans mismatch

Du kan være kjent med begrepet objekt-relasjoner impedans mismatch, som refererer til utfordringen med å kartlegge dataobjekter til en relasjonsdatabase. Denne uoverensstemmelsen oppstår fordi objektorientert design ikke er begrenset til en-til-en, en-til-mange og mange-til-mange relasjoner. I stedet, i objektorientert design, tenker vi på objekter, deres attributter og oppførsel, og hvordan objekter forholder seg. To eksempler er innkapsling og arv:

  • Hvis et objekt inneholder et annet objekt, definerer vi dette gjennom innkapsling--en har en forhold.
  • Hvis et objekt er en spesialisering av et annet objekt, definerer vi dette gjennom arv- en er en forhold.

Assosiasjon, aggregering, komposisjon, abstraksjon, generalisering, realisering og avhengigheter er alle objektorienterte programmeringskonsepter som kan være utfordrende å kartlegge til en relasjonsmodell.

ORM: Objektrelasjonell kartlegging

Misforholdet mellom objektorientert design og relasjonell databasemodellering har ført til en klasse verktøy utviklet spesielt for objektrelasjonell kartlegging (ORM). ORM-verktøy som Hibernate, EclipseLink og iBatis oversetter relasjonsdatabasemodeller, inkludert enheter og deres forhold, til objektorienterte modeller. Mange av disse verktøyene eksisterte før JPA-spesifikasjonen, men uten standard var funksjonene deres avhengig av leverandør.

Java Persistence API (JPA) ble først utgitt som en del av EJB 3.0 i 2006, og tilbyr en standard måte å kommentere objekter slik at de kan kartlegges og lagres i en relasjonsdatabase. Spesifikasjonen definerer også en felles konstruksjon for samhandling med databaser. Å ha en ORM-standard for Java gir konsistens i leverandørimplementeringer, samtidig som det gir mulighet for fleksibilitet og tillegg. Som et eksempel, mens den originale JPA-spesifikasjonen gjelder for relasjonsdatabaser, har noen leverandørimplementeringer utvidet JPA for bruk med NoSQL-databaser.

Utvikling av JPA

Den første utgivelsen av JPA, versjon 1.0, ble utgitt i 2006 gjennom Java Community Process (JCP) som Java Specification Request (JSR) 220. Versjon 2.0 (JSR 317) ble publisert i 2009, versjon 2.1 (JSR 338) i 2013, og versjon 2.2 (en vedlikeholdsutgivelse av JSR 338) ble publisert i 2017. JPA 2.2 er valgt for inkludering og pågående utvikling i Jakarta EE.

Komme i gang med JPA

Java Persistence API er en spesifikasjon, ikke en implementering: den definerer en vanlig abstraksjon som du kan bruke i koden din for å samhandle med ORM-produkter. Denne delen gjennomgår noen av de viktige delene av JPA-spesifikasjonen.

Du lærer hvordan du:

  • Definer enheter, felt og primærnøkler i databasen.
  • Opprett relasjoner mellom enheter i databasen.
  • Arbeid med EntityManager og dens metoder.

Definere enheter

For å definere en enhet, må du opprette en klasse som er merket med @Enhet kommentar. De @Enhet kommentar er en markørkommentar, som brukes til å oppdage vedvarende enheter. Hvis du for eksempel vil opprette en bokenhet, vil du kommentere den som følger:

 @Entity public class Book {...} 

Som standard vil denne enheten bli kartlagt til Bok tabellen, som bestemt av det gitte klassenavnet. Hvis du vil tilordne denne enheten til en annen tabell (og eventuelt et bestemt skjema), kan du bruke @Bord kommentar til å gjøre det. Slik kan du kartlegge Bok klasse til et BOOKS-bord:

 @Entity @Table (name = "BOOKS") offentlig klasse Bok {...} 

Hvis BOOKS-tabellen var i PUBLISHING-skjemaet, kan du legge til skjemaet i @Bord kommentar:

 @Table (name = "BOOKS", schema = "PUBLISERING") 

Kartlegge felt til kolonner

Når enheten er kartlagt til en tabell, er din neste oppgave å definere feltene. Enger er definert som medlemsvariabler i klassen, og navnet på hvert felt blir kartlagt til et kolonnenavn i tabellen. Du kan overstyre denne standardkartleggingen ved å bruke @Kolonne kommentar, som vist her:

 @Entity @Table (name = "BOOKS") offentlig klasse Bok {privat strengnavn; @Column (name = "ISBN_NUMBER") privat streng isbn; ...} 

I dette eksemplet har vi godtatt standardkartleggingen for Navn attributt, men spesifiserte en tilpasset kartlegging for isbn Egenskap. De Navn attributt blir kartlagt til Navn kolonnen, men isbn attributt blir kartlagt til ISBN_NUMBER-kolonnen.

De @Kolonne kommentar tillater oss å definere flere egenskaper for feltet / kolonnen, inkludert lengde, om det er null, om det må være unikt, dets presisjon og skala (hvis det er en desimalverdi), om det kan settes inn og oppdateres, og så videre.

Spesifisere hovednøkkelen

Et av kravene til en relasjonell databasetabell er at den må inneholde en primærnøkkel, eller en nøkkel som unikt identifiserer en bestemt rad i databasen. I JPA bruker vi @Id kommentar for å angi et felt som skal være tabellens primære nøkkel. Primærnøkkelen kreves for å være en primitiv Java-type, en primitiv innpakning, for eksempel Heltall eller Lang, a String, a Dato, a BigInteger, eller a BigDecimal.

I dette eksemplet kartlegger vi id attributt, som er et Heltall, til ID-kolonnen i BOOKS-tabellen:

 @Entity @Table (name = "BOOKS") offentlig klasse Book {@Id private Integer id; privat strengnavn; @Column (name = "ISBN_NUMBER") privat streng isbn; ...} 

Det er også mulig å kombinere @Id kommentar med @Kolonne kommentar for å overskrive primærnøkkelens kolonnenavnkartlegging.

Forhold mellom enheter

Nå som du vet hvordan du definerer en enhet, la oss se på hvordan du kan skape relasjoner mellom enheter. JPA definerer fire merknader for å definere enheter:

  • @OneToOne
  • @OneToMany
  • @ManyToOne
  • @ManyToMany

En-til-en-forhold

De @OneToOne kommentar brukes til å definere en en-til-en-relasjon mellom to enheter. For eksempel kan du ha en Bruker enhet som inneholder brukerens navn, e-postadresse og passord, men det kan være lurt å opprettholde tilleggsinformasjon om en bruker (for eksempel alder, kjønn og favorittfarge) i en separat Brukerprofil enhet. De @OneToOne merknader gjør det lettere å bryte ned data og enheter på denne måten.

De Bruker klassen nedenfor har en singel Brukerprofil forekomst. De Brukerprofil kart til en enkelt Bruker forekomst.

 @Entity public class User {@Id private Integer id; privat streng e-post; privat strengnavn; privat strengpassord; @OneToOne (mappedBy = "bruker") privat brukerprofilprofil; ...} 
 @Entity public class UserProfile {@Id private Integer id; privat alder; privat String kjønn; privat streng favoritt Farge; @OneToOne privat brukerbruker; ...} 

JPA-leverandøren bruker Brukerprofils bruker felt for å kartlegge Brukerprofil til Bruker. Kartleggingen er spesifisert i kartlagt av attributt i @OneToOne kommentar.

En-til-mange og mange-til-en-forhold

De @OneToMany og @ManyToOne merknader letter begge sider av det samme forholdet. Tenk på et eksempel der a Bok kan bare ha en Forfatter, men en Forfatter kan ha mange bøker. De Bok enhet ville definere en @ManyToOne forhold med Forfatter og Forfatter enhet ville definere en @OneToMany forhold med Bok.

 @Entity public class Book {@Id private Integer id; privat strengnavn; @ManyToOne @JoinColumn (name = "AUTHOR_ID") privat forfatterforfatter; ...} 
 @Entity public class Author {@Id @GeneratedValue private Integer id; privat strengnavn; @OneToMany (mappedBy = "forfatter") private Listebøker = ny ArrayList (); ...} 

I dette tilfellet Forfatter klassen fører en liste over alle bøkene som er skrevet av forfatteren og Bok klasse opprettholder en referanse til sin eneste forfatter. I tillegg har @JoinColumn angir navnet på kolonnen i Bok tabell for å lagre IDen til Forfatter.

Mange-til-mange-forhold

Til slutt, @ManyToMany kommentar muliggjør et mange-til-mange forhold mellom enheter. Her er et tilfelle der en Bok enhet har flere Forfatters:

 @Entity public class Book {@Id private Integer id; privat strengnavn; @ManyToMany @JoinTable (name = "BOOK_AUTHORS", joinColumns = @ JoinColumn (name = "BOOK_ID"), inverseJoinColumns = @ JoinColumn (name = "AUTHOR_ID")) private Sett forfattere = ny HashSet (); ...} 
 @Entity public class Author {@Id @GeneratedValue private Integer id; privat strengnavn; @ManyToMany (mappedBy = "forfatter") private Sett bøker = nye HashSet (); ...} 

I dette eksemplet lager vi en ny tabell, BOOK_AUTHORS, med to kolonner: BOOK_ID og AUTHOR_ID. Bruker bli medKolonner og inverseJoinColumns attributter forteller JPA-rammeverket ditt hvordan du kan kartlegge disse klassene i et mange-til-mange forhold. De @ManyToMany kommentar i Forfatter klasse refererer til feltet i Bok klasse som styrer forholdet; nemlig forfattere eiendom.

Det er en rask demo for et ganske komplekst tema. Vi vil dykke videre inn i @JoinTable og @JoinColumn merknader i neste artikkel.

Arbeide med EntityManager

EntityManager er klassen som utfører databaseinteraksjoner i JPA. Den initialiseres gjennom en konfigurasjonsfil med navnet persistence.xml. Denne filen finnes i META-INF mappen i CLASSPATH, som vanligvis er pakket i JAR- eller WAR-filen. De persistence.xml filen inneholder:

  • Den navngitte "utholdenhetsenheten", som spesifiserer utholdenhetsrammeverket du bruker, for eksempel dvalemodus eller EclipseLink.
  • En samling egenskaper som spesifiserer hvordan du kobler til databasen din, samt eventuelle tilpasninger i utholdenhetsrammeverket.
  • En liste over enhetsklasser i prosjektet ditt.

La oss se på et eksempel.

Konfigurere EntityManager

Først lager vi en EntityManager bruker EntityManagerFactory hentet fra Standhaftighet klasse:

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory ("Bøker"); EntityManager entityManager = entityManagerFactory.createEntityManager (); 

I dette tilfellet har vi opprettet en EntityManager som er koblet til "Books" utholdenhet enhet, som vi har konfigurert i persistence.xml fil.

De EntityManager klasse definerer hvordan programvaren vår vil samhandle med databasen gjennom JPA-enheter. Her er noen av metodene som brukes av EntityManager:

  • finne henter en enhet med sin primære nøkkel.
  • createQuery skaper en Spørsmål forekomst som kan brukes til å hente enheter fra databasen.
  • createNamedQuery laster en Spørsmål som er definert i a @NamedQuery kommentar inne i en av utholdenhetsenhetene. Navngitte spørsmål gi en ren mekanisme for sentralisering av JPA-spørsmål i definisjonen av utholdenhetsklassen som spørringen skal utføres på.
  • getTransaction definerer en EntityTransaction å bruke i databaseinteraksjonene dine. Akkurat som databasetransaksjoner, vil du vanligvis starte transaksjonen, utføre operasjonene dine og deretter enten begå eller tilbakebetale transaksjonen. De getTransaction () metoden lar deg få tilgang til denne oppførselen på nivået med EntityManager, i stedet for databasen.
  • slå sammen() legger til en enhet i utholdenhetskonteksten, slik at når transaksjonen blir begått, vil enheten bli videreført til databasen. Når du bruker slå sammen(), objekter håndteres ikke.
  • fortsette legger til en enhet i utholdenhetskonteksten, slik at når transaksjonen er begått, vil enheten bli videreført til databasen. Når du bruker fortsette(), gjenstander administreres.
  • forfriske oppdaterer tilstanden til gjeldende enhet fra databasen.
  • skyll synkroniserer tilstanden til utholdenhetskonteksten med databasen.

Ikke bekymre deg for å integrere alle disse metodene samtidig. Du blir kjent med dem ved å jobbe direkte med EntityManager, som vi vil gjøre mer i neste avsnitt.

$config[zx-auto] not found$config[zx-overlay] not found