Kratki vodič za EntityManager # getReference ()

1. Uvod

The getReference () metoda EntityManager klasa je dio JPA specifikacije od prve verzije. Međutim, ova metoda zbunjuje neke programere jer se njezino ponašanje razlikuje ovisno o osnovnom pružatelju upornosti.

U ovom uputstvu objasnit ćemo kako se koristi getReference () metoda u Hibernate EntityManager.

2. EntityManager Dohvaćanje operacija

Prije svega, pogledat ćemo kako entitete možemo dohvatiti pomoću njihovih primarnih ključeva. Bez pisanja bilo kakvih upita, EntityManager pruža nam dvije osnovne metode da to postignemo.

2.1. pronaći()

pronaći() je najčešća metoda dohvaćanja entiteta:

Igra igra = entityManager.find (Game.class, 1L); 

Ova metoda inicijalizira entitet kada ga zatražimo.

2.2. getReference ()

Slično kao pronaći() metoda, getReference () je također još jedan način za dohvaćanje entiteta:

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

Međutim, vraćeni objekt je entitet proxy koji ima inicijalizirano samo polje primarnog ključa. Ostala polja ostaju nepostavljena, osim ako ih lijeno zatražimo.

Dalje, pogledajmo kako se ove dvije metode ponašaju u različitim scenarijima.

3. Primjer upotrebe

Kako bi demonstrirao EntityManager dohvatiti operacije, stvorit ćemo dva modela, igra i Igrač, kao našu domenu da mnogi igrači mogu biti uključeni u istu igru.

3.1. Model domene

Prvo, definirajmo entitet koji se zove Igra:

@ Entity javna klasa igra {@Id private Long id; privatni naziv niza; // standardni konstruktori, getteri, postavljači} 

Dalje, definiramo svoje Igrač entitet:

@ Entity javna klasa Player {@Id private Long id; privatni naziv niza; // standardni konstruktori, getteri, postavljači} 

3.2. Konfiguriranje odnosa

Moramo konfigurirati a @ManyToOne odnos iz Igrač do igra. Dakle, dodajmo a igra vlasništvo našem Igrač entitet:

@ManyToOne privatna igra; 

4. Ispitni slučajevi

Prije nego što započnemo s pisanjem metoda ispitivanja, dobra je praksa zasebno definirati podatke o ispitivanju:

entityManager.getTransaction (). begin (); entityManager.persist (nova igra (1L, "Igra 1")); entityManager.persist (nova igra (2L, "Igra 2")); entityManager.persist (novi Player (1L, "Player 1")); entityManager.persist (novi Player (2L, "Player 2")); entityManager.persist (novi Player (3L, "Player 3")); entityManager.getTransaction (). commit (); 

Uz to, da bismo ispitali temeljne SQL upite, trebali bismo konfigurirati hibernate hibernate.show_sql imovine u našem postojanost.xml:

4.1. Ažuriranje polja entiteta

Prvo ćemo provjeriti najčešći način ažuriranja entiteta pomoću pronaći() metoda.

Pa, napišimo test metodu za dohvaćanje igra entitet, a zatim jednostavno ažurirajte svoj Ime polje:

Igra game1 = entityManager.find (Game.class, 1L); game1.setName ("Igra ažurirana 1"); entityManager.persist (igra1); 

Pokretanje metode ispitivanja pokazuje nam izvršene SQL upite:

Hibernate: odaberite game0_.id kao id1_0_0_, game0_.name kao name2_0_0_ iz Game game0_ gdje game0_.id =? Hibernate: ažuriranje naziva skupa igara =? gdje id =? 

Kao što primjećujemo, the ODABERI upit u tom slučaju izgleda nepotrebno. Budući da ne trebamo čitati nijedno polje igra entitet prije našeg postupka ažuriranja, pitamo se postoji li neki način izvršenja samo AŽURIRANJE upit.

Pa, da vidimo kako getReference () metoda ponaša se u istom scenariju:

Igra game1 = entityManager.getReference (Game.class, 1L); game1.setName ("Igra ažurirana 2"); entityManager.persist (igra1); 

Iznenađujuče, rezultat metode tekućeg ispitivanja je i dalje isti i vidimo ODABERI upit ostaje.

Kao što vidimo, Hibernate izvršava a ODABERI upit kada koristimo getReference () za ažuriranje polja entiteta.

Stoga, koristiti getReference () metoda ne izbjegava suvišno ODABERI upit izvršimo li bilo koji postavljač polja proxy entiteta.

4.2. Brisanje entiteta

Sličan se scenarij može dogoditi kada izvršimo operacije brisanja.

Definirajmo još dvije metode ispitivanja za brisanje a Igrač entitet:

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

Pokretanje ovih metoda ispitivanja pokazuju nam iste upite:

Hibernate: odaberite player0_.id kao id1_1_0_, player0_.game_id kao game_id3_1_0_, player0_.name kao name2_1_0_, game1_.id kao id1_0_1_, game1_.name kao name2_0_1_ iz Player player0_ lijevo vanjsko pridruživanje Game game1_ na player0_.game_id = game_0.game_id = igra .id =? Hibernate: brisanje iz programa Player gdje je id =? 

Isto tako, za operacije brisanja rezultat je sličan. Čak i ako ne čitamo nijedno polje Igrač entiteta, Hibernate izvršava dodatni ODABERI upit također.

Stoga, nema razlike da li ćemo odabrati getReference () ili pronaći() metoda kada brišemo postojeći entitet.

U ovom trenutku, pitamo se, ima li getReference () napraviti ikakvu razliku onda? Prijeđimo na entitetske odnose i saznajmo.

4.3. Ažuriranje odnosa entiteta

Još jedan uobičajeni slučaj upotrebe pojavljuje se kada moramo spasiti odnose između naših entiteta.

Dodajmo još jednu metodu za pokazivanje a Igrač‘Sudjelovanje u a igra jednostavnim ažuriranjem Igrač‘S igra svojstvo:

Igra game1 = entityManager.find (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game1); entityManager.persist (igrač1); 

Pokretanje testa daje nam sličan rezultat još jednom i još uvijek možemo vidjeti ODABERI upite kada se koristi pronaći() metoda:

Hibernate: odaberite game0_.id kao id1_0_0_, game0_.name kao name2_0_0_ iz Game game0_ gdje game0_.id =? Hibernate: odaberite player0_.id kao id1_1_0_, player0_.game_id kao game_id3_1_0_, player0_.name kao name2_1_0_, game1_.id kao id1_0_1_, game1_.name kao name2_0_1_ iz Player player0_ lijevo vanjsko pridruživanje Game game1_ na player0_.game_id = game_0.game_id = igra .id =? Hibernate: ažuriranje Player set game_id = ?, name =? gdje id =? 

Ajmo sada definirati još jedan test za vidjeti kako getReference () metoda djeluje u ovom slučaju:

Igra game2 = entityManager.getReference (Game.class, 2L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game2); entityManager.persist (igrač1); 

Nadamo se da će nam pokretanje testa dati očekivano ponašanje:

Hibernate: odaberite player0_.id kao id1_1_0_, player0_.game_id kao game_id3_1_0_, player0_.name kao name2_1_0_, game1_.id kao id1_0_1_, game1_.name kao name2_0_1_ iz Player player0_ lijevo vanjsko pridruživanje Game game1_ na player0_.game_id = game_0.game_id = igra .id =? Hibernate: ažuriranje Player set game_id = ?, name =? gdje id =? 

I vidimo, Hibernate ne izvršava a ODABERI upit za igra entitet kada koristimo getReference () ovaj put.

Dakle, izgleda kao dobra praksa za odabir getReference () u ovom slučaju. To je zato što je proxy igra entiteta dovoljan je da stvori odnos iz Igrač entitet - igra entitet ne mora biti inicijaliziran.

Slijedom toga, koristeći getReference () može eliminirati nepotrebna povratna putovanja u našu bazu podataka kada ažuriramo odnose entiteta.

5. Hibernate predmemorija prve razine

To ponekad može zbuniti obje metode pronaći() i getReference () ne može izvršiti nijedan ODABERI upiti u nekim slučajevima.

Zamislimo situaciju da su naši entiteti već učitani u kontekstu postojanosti prije naše operacije:

entityManager.getTransaction (). begin (); entityManager.persist (nova igra (1L, "Igra 1")); entityManager.persist (novi Player (1L, "Player 1")); entityManager.getTransaction (). commit (); entityManager.getTransaction (). begin (); Igra game1 = entityManager.getReference (Game.class, 1L); Player player1 = entityManager.find (Player.class, 1L); player1.setGame (game1); entityManager.persist (igrač1); entityManager.getTransaction (). commit (); 

Pokretanje testa pokazuje da je izvršen samo upit za ažuriranje:

Hibernate: ažuriranje Player set game_id = ?, name =? gdje id =? 

U takvom bismo slučaju to trebali primijetiti ne vidimo nijednu ODABERI upiti, koristimo li pronaći() ili getReference (). To je zato što su naši entiteti predmemorirani u Hibernate-ovoj prvorazrednoj predmemoriji.

Kao rezultat, kada su naši entiteti pohranjeni u Hibernate-ovoj predmemoriji prve razine, onda oboje pronaći() i getReference () metode djeluju identično i ne pogađaju našu bazu podataka.

6. Različite provedbe JPA-e

Kao posljednji podsjetnik, trebali bismo biti svjesni da ponašanje getReference () metoda ovisi o osnovnom pružatelju upornosti.

Prema JPA 2 specifikaciji, pružatelj trajnosti smije baciti EntityNotFoundException kada getReference () metoda se naziva. Stoga to može biti drugačije za druge pružatelje upornosti i možemo se susresti EntityNotFoundException kad koristimo getReference ().

Štoviše, Hibernate ne slijedi specifikaciju za getReference () prema zadanim postavkama spremanje povratnog putovanja do baze podataka kada je to moguće. Sukladno tome, ne donosi iznimku kada dohvatimo entitete-proxyje, čak i ako oni ne postoje u bazi podataka.

Alternativno, Hibernate nudi svojstvo konfiguracije kako bi ponudio pouzdan način onima koji žele slijediti JPA specifikaciju.

U takvom slučaju možemo razmisliti o postavljanju hibernate.jpa.compliance.proxy svojstvo da pravi:

Ovom postavkom Hibernate inicijalizira entitet proxy u svakom slučaju, što znači da izvršava a ODABERI upit čak i kada koristimo getReference ().

7. Zaključak

U ovom smo uputstvu istražili neke slučajeve upotrebe koji mogu imati koristi od referentnih proxy objekata i naučili kako ih koristiti EntityManager‘S getReference () metoda u hibernaciji.

Kao i uvijek, svi uzorci koda i više test slučajeva za ovaj vodič su dostupni na GitHub-u.


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