Stručný sprievodca k EntityManager # getReference ()

1. Úvod

The getReference () metóda EntityManager triedy je súčasťou špecifikácie JPA od prvej verzie. Táto metóda však niektorých vývojárov mätie, pretože jej správanie sa líši v závislosti od základného poskytovateľa perzistencie.

V tomto výučbe vysvetlíme, ako používať getReference () metóda v Hibernácia EntityManager.

2. EntityManager Operácie načítania

Najskôr sa pozrieme na to, ako môžeme načítať entity podľa ich primárnych kľúčov. Bez písania dotazov EntityManager poskytuje dve základné metódy, ako to dosiahnuť.

2.1. Nájsť()

Nájsť() je najbežnejšia metóda načítania entít:

Hra hra = entityManager.find (Game.class, 1L); 

Táto metóda inicializuje entitu, keď ju požadujeme.

2.2. getReference ()

Podobne ako v Nájsť() metóda, getReference () je tiež ďalší spôsob, ako načítať entity:

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

Vrátený objekt je však proxy entity, ktorá má inicializované iba pole primárneho kľúča. Ostatné polia zostávajú neaktívne, pokiaľ o ne lenivo nepožiadame.

Ďalej sa pozrime, ako sa tieto dve metódy správajú v rôznych scenároch.

3. Príklad použitia

S cieľom demonštrovať EntityManager operácie načítania, vytvoríme dva modely, Hra a Hráč, ako naša doména môže byť do jednej hry zapojených veľa hráčov.

3.1. Doménový model

Najskôr definujme entitu s názvom Hra:

@Entity Public Class Game {@Id private Long id; súkromné ​​meno reťazca; // štandardné konštruktory, getre, setre} 

Ďalej definujeme naše Prehrávač subjekt:

@Entity public class Player {@Id private Long id; súkromné ​​meno reťazca; // štandardné konštruktory, getre, setre} 

3.2. Konfigurácia vzťahov

Musíme nakonfigurovať a @ManyToOne vzťah z Prehrávač do Hra. Pridajme teda a hra majetok k nášmu Prehrávač subjekt:

@ManyToOne súkromná hra; 

4. Testovacie prípady

Skôr ako začneme písať naše testovacie metódy, je dobrým zvykom definovať naše testovacie údaje osobitne:

entityManager.getTransaction (). begin (); entityManager.persist (nová hra (1L, „hra 1“)); entityManager.persist (nová hra (2L, „hra 2“)); entityManager.persist (nový prehrávač (1L, "prehrávač 1")); entityManager.persist (nový hráč (2L, "hráč 2")); entityManager.persist (nový hráč (3L, "hráč 3")); entityManager.getTransaction (). commit (); 

Okrem toho by sme mali preskúmať základné dotazy SQL nakonfigurovať režim dlhodobého spánku hibernate.show_sql nehnuteľnosť v našom persistence.xml:

4.1. Aktualizujú sa polia entít

Najskôr skontrolujeme najbežnejší spôsob aktualizácie entity pomocou Nájsť() metóda.

Poďme teda napísať testovaciu metódu na získanie súboru Hra subjekt najskôr aktualizujte názov lúka:

Hra game1 = entityManager.find (Game.class, 1L); game1.setName ("Hra aktualizovaná 1"); entityManager.persist (hra1); 

Spustenie testovacej metódy nám ukazuje vykonané dotazy SQL:

Hibernácia: vyberte game0_.id ako id1_0_0_, game0_.name ako name2_0_0_ z Game game0_ kde game0_.id =? Hibernate: update Game set name =? kde id =? 

Ako sme si všimli, the VYBERTE dopyt v takom prípade vyzerá zbytočne. Pretože nepotrebujeme čítať žiadne pole z Hra entity pred našou aktualizačnou operáciou, zaujíma nás, či existuje nejaký spôsob, ako vykonať iba AKTUALIZÁCIA dopyt.

Pozrime sa teda, ako getReference () metóda sa správa v rovnakom scenári:

Hra game1 = entityManager.getReference (Game.class, 1L); game1.setName ("Hra aktualizovaná 2"); entityManager.persist (hra1); 

Prekvapivo výsledok testovacej metódy je stále rovnaký a vidíme VYBERTE dopyt zostáva.

Ako vidíme, režim dlhodobého spánku vykoná a VYBERTE dotaz, keď používame getReference () aktualizovať pole entity.

Preto pomocou getReference () metóda sa nevyhne extra VYBERTE dotaz, ak vykonáme ľubovoľného nastavovača polí proxy entity.

4.2. Mazanie entít

Podobný scenár sa môže stať, keď vykonáme operácie odstránenia.

Definujme ďalšie dve testovacie metódy na odstránenie a Prehrávač subjekt:

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

Spustenie týchto testovacích metód nám ukazuje rovnaké dotazy:

Hibernácia: vyberte player0_.id ako id1_1_0_, player0_.game_id ako game_id3_1_0_, player0_.name ako name2_1_0_, game1_.id ako id1_0_1_, game1_.name ako name2_0_1_ z Player player0_ ľavé vonkajšie spojenie Game1_ na player0_.game_id = game1__lide = game1_ .id =? Hibernate: delete from Player where id =? 

Rovnako aj pri operáciách mazania je výsledok podobný. Aj keď nečítame žiadne polia súboru Prehrávač jednotka dlhodobého spánku vykoná ďalšiu VYBERTE dopyt tiež.

Teda nie je rozdiel, či sa rozhodneme getReference () alebo Nájsť() keď odstránime existujúcu entitu.

V tejto chvíli by nás zaujímalo, že getReference () urobiť potom vôbec nejaký rozdiel? Prejdime k vzťahom medzi entitami a zistíme.

4.3. Aktualizácia vzťahov s entitami

Iný bežný prípad použitia sa objaví, keď potrebujeme zachrániť vzťahy medzi našimi entitami.

Pridajme ďalšiu metódu na demonštráciu a PrehrávačÚčasť na a Hra jednoduchou aktualizáciou Prehrávač‘S hra nehnuteľnosť:

Hra game1 = entityManager.find (Game.class, 1L); Hráč player1 = entityManager.find (Player.class, 1L); player1.setGame (hra1); entityManager.persist (player1); 

Spustenie testu nám poskytne podobný výsledok ešte raz a stále môžeme vidieť VYBERTE otázky pri použití Nájsť() metóda:

Hibernácia: vyberte game0_.id ako id1_0_0_, game0_.name ako name2_0_0_ z Game game0_ kde game0_.id =? Hibernácia: vyberte player0_.id ako id1_1_0_, player0_.game_id ako game_id3_1_0_, player0_.name ako name2_1_0_, game1_.id ako id1_0_1_, game1_.name ako name2_0_1_ z Player player0_ ľavé vonkajšie spojenie Game1_ na player0_.game_id = game1__lide = game1_ .id =? Hibernate: update Player set game_id = ?, name =? kde id =? 

Teraz definujeme ešte jeden test pozri ako getReference () metóda funguje v tomto prípade:

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

Dúfajme, že vykonanie testu nám dá očakávané správanie:

Hibernácia: vyberte player0_.id ako id1_1_0_, player0_.game_id ako game_id3_1_0_, player0_.name ako name2_1_0_, game1_.id ako id1_0_1_, game1_.name ako name2_0_1_ z Player player0_ ľavé vonkajšie spojenie Game1_ na player0_.game_id = game1__lide = game1_ .id =? Hibernate: update Player set game_id = ?, name =? kde id =? 

A vidíme, Hibernate nevykonáva a VYBERTE dopyt na Hra entita, keď používame getReference () tentokrát.

Vyzerá to teda ako dobrý postup getReference () v tomto prípade. To preto, že splnomocnenec Hra entita stačí na vytvorenie vzťahu z Prehrávač subjekt - Hra subjekt nemusí byť inicializovaný.

V dôsledku toho použitím getReference () dokáže eliminovať zbytočné spiatočné lety do našej databázy pri aktualizácii vzťahov medzi entitami.

5. Hibernácia vyrovnávacej pamäte prvej úrovne

Môže to byť niekedy mätúce obidve metódy Nájsť() a getReference () nemusí vykonávať žiadne VYBERTE v niektorých prípadoch otázky.

Poďme si predstaviť situáciu, že naše entity sú už pred našou operáciou načítané v kontexte perzistencie:

entityManager.getTransaction (). begin (); entityManager.persist (nová hra (1L, „hra 1“)); entityManager.persist (nový hráč (1L, "hráč 1")); entityManager.getTransaction (). commit (); entityManager.getTransaction (). begin (); Hra game1 = entityManager.getReference (Game.class, 1L); Hráč player1 = entityManager.find (Player.class, 1L); player1.setGame (hra1); entityManager.persist (player1); entityManager.getTransaction (). commit (); 

Spustenie testu ukazuje, že sa vykonal iba aktualizačný dotaz:

Hibernate: update Player set game_id = ?, name =? kde id =? 

V takom prípade by sme si to mali všimnúť nevidíme žiadne VYBERTE dotazy, či použijeme Nájsť() alebo getReference (). Je to tak preto, lebo naše entity sú uložené v medzipamäti prvej úrovne spoločnosti Hibernate.

Ako výsledok, keď sú naše entity uložené v medzipamäte prvej úrovne režimu spánku, potom obidve Nájsť() a getReference () metódy konajú identicky a nenarazia na našu databázu.

6. Rôzne implementácie JPA

Na záver by sme si mali uvedomiť, že správanie sa spoločnosti getReference () metóda závisí od základného poskytovateľa perzistencie.

Podľa špecifikácie JPA 2 je poskytovateľ vytrvalosti oprávnený odhodiť EntityNotFoundException keď getReference () metóda sa volá. Môže to teda byť iné pre ostatných poskytovateľov perzistencie a môžeme sa s nimi stretnúť EntityNotFoundException keď používame getReference ().

Napriek tomu Hibernate nedodržiava špecifikáciu pre getReference () predvolene, ak je to možné, uložiť spiatočnú cestu k databáze. Preto nevyvoláva výnimku, keď načítame proxy serverov entít, aj keď v databáze neexistujú.

Prípadne Hibernate poskytuje konfiguračnú vlastnosť, ktorá ponúka namyslený spôsob pre tých, ktorí sa chcú riadiť špecifikáciou JPA.

V takom prípade môžeme zvážiť nastavenie hibernate.jpa.compliance.proxy majetok do pravda:

Pri tomto nastavení režim dlhodobého spánku inicializuje v každom prípade proxy entity, čo znamená, že vykoná a VYBERTE dotaz, aj keď používame getReference ().

7. Záver

V tomto tutoriáli sme preskúmali niektoré prípady použitia, ktoré môžu ťažiť z referenčných proxy objektov, a naučili sme sa, ako ich používať EntityManager‘S getReference () metóda v režime dlhodobého spánku.

Ako vždy, všetky ukážky kódu a ďalšie testovacie prípady pre tento tutoriál sú k dispozícii na GitHub.


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