Hurtig guide til EntityManager # getReference ()

1. Introduktion

Det getReference () metode til EntityManager klasse har været en del af JPA-specifikationen siden den første version. Denne metode forvirrer dog nogle udviklere, fordi dens opførsel varierer afhængigt af den underliggende udholdenhedsudbyder.

I denne vejledning skal vi forklare, hvordan du bruger getReference () metode i Dvaletilstand EntityManager.

2. EntityManager Hent operationer

Først og fremmest skal vi se på, hvordan vi kan hente enheder ved deres primære nøgler. Uden at skrive spørgsmål EntityManager giver os to grundlæggende metoder til at opnå dette.

2.1. finde()

finde() er den mest almindelige metode til at hente enheder:

Spil spil = entityManager.find (Game.class, 1L); 

Denne metode initialiserer enheden, når vi anmoder om det.

2.2. getReference ()

Svarende til finde() metode, getReference () er også en anden måde at hente enheder på:

Game game = entityManager.getReference (Game.class, 1L); 

Det returnerede objekt er dog en enhedsproxy, der kun har det primære nøglefelt initialiseret. De andre felter forbliver usæt, medmindre vi dovent anmoder om dem.

Lad os derefter se, hvordan disse to metoder opfører sig i forskellige scenarier.

3. Et eksempel på brugssag

For at demonstrere EntityManager hent operationer, vi opretter to modeller, Spil og Spiller, som vores domæne, at mange spillere kan være involveret i det samme spil.

3.1. Domæne Model

Lad os først definere en kaldet enhed Spil:

@Entity offentlig klassespil {@Id privat Lang id; privat strengnavn; // standard konstruktører, getters, setters} 

Dernæst definerer vi vores Spiller enhed:

@Entity public class Player {@Id privat Lang id; privat strengnavn; // standard konstruktører, getters, setters} 

3.2. Konfiguration af relationer

Vi er nødt til konfigurer en @ManyToOne forhold fra Spiller til Spil. Så lad os tilføje en spil ejendom til vores Spiller enhed:

@ManyToOne privat spil spil; 

4. Test tilfælde

Før vi begynder at skrive vores testmetoder, er det en god praksis at definere vores testdata separat:

entityManager.getTransaction (). begynder (); entityManager.persist (nyt spil (1L, "spil 1")); entityManager.persist (nyt spil (2L, "spil 2")); entityManager.persist (ny spiller (1L, "Player 1")); entityManager.persist (ny spiller (2L, "Player 2")); entityManager.persist (ny spiller (3L, "Player 3")); entityManager.getTransaction (). commit (); 

Derudover skal vi for at undersøge underliggende SQL-forespørgsler konfigurer dvaletilstand dvale.show_sql ejendom i vores persistence.xml:

4.1. Opdatering af enhedsfelter

Først kontrollerer vi den mest almindelige måde at opdatere en enhed på ved hjælp af finde() metode.

Så lad os skrive en testmetode for at hente Spil enhed først og derefter blot opdatere dens navn Mark:

Spil game1 = entityManager.find (Game.class, 1L); game1.setName ("Spil opdateret 1"); entityManager.persist (game1); 

Kørsel af testmetoden viser os de udførte SQL-forespørgsler:

Dvaletilstand: vælg game0_.id som id1_0_0_, game0_.name som name2_0_0_ fra Game game0_ hvor game0_.id =? Dvaletilstand: opdater spil sæt navn =? hvor id =? 

Som vi bemærker, det VÆLG forespørgsel ser unødvendig ud i et sådant tilfælde. Da vi ikke behøver at læse noget felt i Spil enhed før vores opdateringsoperation, vi spekulerer på, om der kun er nogen måde at udføre OPDATER forespørgsel.

Så lad os se hvordan getReference () metode opfører sig i samme scenarie:

Spil game1 = entityManager.getReference (Game.class, 1L); game1.setName ("Spil opdateret 2"); entityManager.persist (game1); 

Overraskende nok resultatet af den kørende testmetode er stadig det samme, og vi ser VÆLG forespørgsel forbliver.

Som vi kan se, udfører dvale en VÆLG forespørgsel, når vi bruger getReference () for at opdatere et enhedsfelt.

Derfor, bruger getReference () metoden undgår ikke det ekstra VÆLG forespørgsel, hvis vi udfører en setter af enhedsproxyens felter.

4.2. Sletning af enheder

Et lignende scenarie kan ske, når vi udfører sletteoperationer.

Lad os definere yderligere to testmetoder til at slette en Spiller enhed:

Player player2 = entityManager.find (Player.class, 2L); entityManager.remove (player2); 
Player player3 = entityManager.getReference (Player.class, 3L); entityManager.remove (player3); 

At køre disse testmetoder viser os de samme forespørgsler:

Dvaletilstand: vælg spiller0_.id som id1_1_0_, spiller0_.game_id som spil_id3_1_0_, spiller0_.navn som navn2_1_0_, spil1_.id som id1_0_1_, spil1_.navn som navn2_0_1_ fra Player player0_ venstre ydre join Game game1_ på player0_.game_id = game_ .id =? Dvaletilstand: slet fra afspiller hvor id =? 

Til sletning er resultatet ligeledes ens. Selv hvis vi ikke læser nogen felter i Spiller enhed, udfører dvale en ekstra VÆLG forespørgsel også.

Derfor, der er ingen forskel, om vi vælger getReference () eller finde() metode, når vi sletter en eksisterende enhed.

På dette tidspunkt undrer vi os over, gør getReference () gøre nogen forskel overhovedet da? Lad os gå videre til enhedsrelationer og finde ud af det.

4.3. Opdatering af enhedsrelationer

En anden almindelig brugssag vises, når vi har brug for at redde forholdet mellem vores enheder.

Lad os tilføje en anden metode til at demonstrere en Spiller'S deltagelse i en Spil ved blot at opdatere Spiller'S spil ejendom:

Spil game1 = entityManager.find (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (spil1); entityManager.persist (spiller1); 

At køre testen giver os et lignende resultat en gang til og vi kan stadig se VÆLG forespørgsler, når du bruger finde() metode:

Dvaletilstand: vælg game0_.id som id1_0_0_, game0_.name som name2_0_0_ fra Game game0_ hvor game0_.id =? Dvaletilstand: vælg spiller0_.id som id1_1_0_, spiller0_.game_id som game_id3_1_0_, player0_.name som name2_1_0_, game1_.id som id1_0_1_, game1_.name som name2_0_1_ fra Player player0_ venstre ydre join Game game1_ på player0_.game_id = spiller_ .id =? Dvaletilstand: opdater afspiller sæt game_id = ?, navn =? hvor id =? 

Lad os nu definere endnu en test til se hvordan getReference () metoden fungerer i dette tilfælde:

Spil game2 = entityManager.getReference (Game.class, 2L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (spil2); entityManager.persist (spiller1); 

Forhåbentlig giver os at køre testen den forventede adfærd:

Dvaletilstand: vælg spiller0_.id som id1_1_0_, spiller0_.game_id som game_id3_1_0_, player0_.name som name2_1_0_, game1_.id som id1_0_1_, game1_.name som name2_0_1_ fra Player player0_ venstre ydre join Game game1_ på player0_.game_id = spiller_ .id =? Dvaletilstand: opdater afspiller sæt game_id = ?, navn =? hvor id =? 

Og vi ser, Dvaletilstand udfører ikke a VÆLG forespørgsel til Spil enhed, når vi bruger getReference () denne gang.

Så det ser ud som en god praksis at vælge getReference () I dette tilfælde. Det er fordi en proxy Spil enhed er nok til at skabe forholdet fra Spiller enhed - Spil enhed behøver ikke at blive initialiseret.

Følgelig, ved brug af getReference () kan eliminere unødvendige rundrejser til vores database, når vi opdaterer enhedsrelationer.

5. Dvale første niveau cache

Det kan undertiden være forvirrende begge metoder finde() og getReference () må ikke udføre nogen VÆLG forespørgsler i nogle tilfælde.

Lad os forestille os en situation, hvor vores enheder allerede er indlæst i vedholdenhedskonteksten før vores operation:

entityManager.getTransaction (). begynder (); entityManager.persist (nyt spil (1L, "spil 1")); entityManager.persist (ny spiller (1L, "Player 1")); entityManager.getTransaction (). commit (); entityManager.getTransaction (). begynder (); Spil game1 = entityManager.getReference (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (spil1); entityManager.persist (spiller1); entityManager.getTransaction (). commit (); 

Kørsel af testen viser, at kun opdateringsforespørgslen blev udført:

Dvaletilstand: opdater afspiller sæt game_id = ?, navn =? hvor id =? 

I et sådant tilfælde skal vi bemærke det vi kan ikke se nogen VÆLG forespørgsler, om vi bruger finde() eller getReference (). Dette skyldes, at vores enheder er cachelagret i dvaleens cache på første niveau.

Som resultat, når vores enheder er gemt i dvaleens første niveau cache, så begge finde() og getReference () metoder fungerer identiske og rammer ikke vores database.

6. Forskellige JPA-implementeringer

Som en sidste påmindelse skal vi være opmærksomme på, at adfærden for getReference () metode afhænger af den underliggende udbyder af persistens.

I henhold til JPA 2-specifikationen har udholdenhedsudbyderen lov til at kaste EntityNotFoundException når getReference () metode kaldes. Således kan det være anderledes for andre udholdenhedsudbydere, og vi kan støde på EntityNotFoundException når vi bruger getReference ().

Alligevel, Dvaletilstand følger ikke specifikationen for getReference () som standard for at gemme en database rundtur, når det er muligt. Derfor kaster det ikke en undtagelse, når vi henter enhedsproxyer, selvom de ikke findes i databasen.

Alternativt Hibernate giver en konfigurationsegenskab til at tilbyde en meningsfuld måde for dem, der ønsker at følge JPA-specifikationen.

I et sådant tilfælde kan vi overveje at indstille hibernate.jpa.compliance.proxy ejendom til rigtigt:

Med denne indstilling initialiserer dvale under alle omstændigheder enhedsproxyen, hvilket betyder, at den udfører en VÆLG forespørgsel, selv når vi bruger getReference ().

7. Konklusion

I denne vejledning undersøgte vi nogle brugssager, der kan drage fordel af referenceproxyobjekterne, og lærte at bruge EntityManager'S getReference () metode i dvale.

Som altid er alle kodeeksempler og flere testcases til denne tutorial tilgængelige på GitHub.


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