Rövid útmutató az EntityManagerhez # getReference ()

1. Bemutatkozás

A getReference () módszere EntityManager osztály az első verzió óta része a JPA specifikációjának. Ez a módszer azonban megzavarja egyes fejlesztőket, mivel viselkedése az alapul szolgáló perzisztencia-szolgáltatótól függ.

Ebben az oktatóanyagban elmagyarázzuk a getReference () módszer ben Hibernálás EntityManager.

2. EntityManager Letöltési műveletek

Először is megvizsgáljuk, hogyan lehet az entitásokat lekérni az elsődleges kulcsokkal. Kérdések írása nélkül, EntityManager két alapvető módszert biztosít számunkra ennek elérésére.

2.1. megtalálja()

megtalálja() a legelterjedtebb módszer az entitások lekérésére:

Játék játék = entityManager.find (Game.class, 1L); 

Ez a módszer inicializálja az entitást, amikor kérjük.

2.2. getReference ()

Hasonló a megtalálja() módszer, getReference () az entitások lekérésének egy másik módja:

Játék játék = entityManager.getReference (Game.class, 1L); 

A visszaküldött tárgy azonban az olyan entitás proxy, amelynek csak az elsődleges kulcsmező inicializálva van. A többi mező nincs beállítva, hacsak nem lustán kérjük őket.

Ezután nézzük meg, hogyan viselkedik ez a két módszer a különböző forgatókönyvekben.

3. Példa felhasználási esetre

Annak demonstrálása érdekében EntityManager letöltési műveletekkel két modellt hozunk létre, Játszma, meccs és Játékos, domainünkként, hogy sok játékos részt vehet ugyanabban a játékban.

3.1. Domain modell

Először definiáljunk egy nevű entitást Játszma, meccs:

@Entity public class Game {@Id private Long id; privát karakterlánc neve; // szabványos kivitelezők, szerelők, beállítók} 

Ezután meghatározzuk a sajátunkat Játékos entitás:

@Entity public class Player {@Id private Long id; privát karakterlánc neve; // szabványos kivitelezők, szerelők, beállítók} 

3.2. Kapcsolatok beállítása

Meg kell konfigurálja a @ManyToOne viszony Játékos nak nek Játszma, meccs. Tehát tegyünk hozzá egy játszma, meccs tulajdon a mi Játékos entitás:

@ManyToOne privát játék játék; 

4. Tesztesetek

Mielőtt elkezdenénk írni vizsgálati módszereinket, célszerű külön meghatározni a vizsgálati adatainkat:

entitásManager.getTransaction (). begin (); entitManager.persist (új játék (1L, "1. játék")); entitManager.persist (új játék (2L, "2. játék")); entityManager.persist (új lejátszó (1L, "Player 1")); entityManager.persist (új lejátszó (2L, "2. játékos")); entityManager.persist (új lejátszó (3L, "Player 3")); entitásManager.getTransaction (). kötelezettség (); 

Ezenkívül meg kell vizsgálnunk az alapul szolgáló SQL lekérdezéseket konfigurálja a hibernáltakat hibernate.show_sql ingatlan miénkben kitartás.xml:

4.1. Entitásmezők frissítése

Először ellenőrizzük az entitás frissítésének leggyakoribb módját a megtalálja() módszer.

Tehát írjunk egy tesztmódszert a Játszma, meccs először, majd egyszerűen frissítse azt név terület:

Game game1 = entityManager.find (Game.class, 1L); game1.setName ("Játék frissítve 1"); entitásManager.persist (játék1); 

A teszt módszer futtatása megmutatja a végrehajtott SQL lekérdezéseket:

Hibernálás: válassza a game0_.id nevet id1_0_0_, a game0_.name nevet2_0_0_ a Game game0_ mezőből, ahol game0_.id =? Hibernálás: frissítse a játékkészlet nevét =? ahol id =? 

Ahogy észrevesszük, a SELECT a lekérdezés ilyen esetben feleslegesnek tűnik. Mivel nem kell elolvasnunk a Játszma, meccs entitás előtt a frissítési műveletünk, arra vagyunk kíváncsiak, hogy van-e valamilyen módja csak a FRISSÍTÉS lekérdezés.

Tehát nézzük meg, hogyan getReference () metódus ugyanabban a forgatókönyvben viselkedik:

Game game1 = entitásManager.getReference (Game.class, 1L); game1.setName ("Játék frissítve 2"); entitásManager.persist (játék1); 

Meglepően, a futó teszt módszer eredménye továbbra is ugyanaz, és látjuk a SELECT a lekérdezés megmarad.

Mint láthatjuk, a Hibernate végrehajtja a SELECT lekérdezés, amikor használjuk getReference () egy entitás mező frissítéséhez.

Ebből kifolyólag, használni a getReference () módszer nem kerüli el az extrát SELECT lekérdezzük, ha az entitás proxy mezőinek bármely szetterét végrehajtjuk.

4.2. Entitások törlése

Hasonló forgatókönyv történhet, ha törlési műveleteket hajtunk végre.

Határozzunk meg további két vizsgálati módszert az a törléséhez Játékos entitás:

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

Ezeknek a vizsgálati módszereknek a futtatása ugyanazokat a kérdéseket mutatja nekünk:

Hibernálás: válassza a player0_.id nevet id1_1_0_, player0_.game_id mint game_id3_1_0_, player0_.name nevet2_1_0_, game1_.id mint id1_0_1_, game1_.name nevet2_0_1_ a Player player0_ bal külsõ csatlakozáshoz Game game1_ on player0_.game_id = game1 .id =? Hibernálás: törlés a lejátszóról, ahol id =? 

Hasonlóképpen, a törlési műveletek esetében az eredmény hasonló. Még akkor is, ha a Játékos entitás, a Hibernate végrehajt egy kiegészítőt SELECT lekérdezés is.

Ennélfogva, nincs különbség, hogy választunk-e getReference () vagy megtalálja() módszer, amikor törölünk egy létező entitást.

Ezen a ponton kíváncsiak vagyunk, nem getReference () akkor van egyáltalán különbség? Térjünk át az entitáskapcsolatokra, és derítsük ki.

4.3. Entitáskapcsolatok frissítése

Egy másik gyakori felhasználási eset akkor jelenik meg, amikor meg kell mentenünk entitásaink közötti kapcsolatokat.

Adjunk hozzá egy másik módszert a Játékos’Részvétele a Játszma, meccs egyszerűen frissítve a Játékos’S játszma, meccs ingatlan:

Game game1 = entityManager.find (Game.class, 1L); Player player1 = entitásManager.find (Player.class, 1L); player1.setGame (game1); entitásManager.persist (player1); 

A teszt lefuttatása még egyszer hasonló eredményt ad nekünk és még mindig láthatjuk a SELECT lekérdezések a megtalálja() módszer:

Hibernálás: válassza a game0_.id nevet id1_0_0_, a game0_.name nevet2_0_0_ a Game game0_ mezőből, ahol game0_.id =? Hibernálás: válassza a player0_.id nevet id1_1_0_, player0_.game_id mint game_id3_1_0_, player0_.name nevet2_1_0_, game1_.id mint id1_0_1_, game1_.name mint name2_0_1_ a Player player0_ bal külső csatlakozáshoz Game game1_ on player0_.game_id = game1 .id =? Hibernálás: Frissítse a lejátszót a game_id = ?, name =? ahol id =? 

Most definiáljunk még egy tesztet látni, hogy a getReference () módszer ebben az esetben működik:

Game game2 = entitásManager.getReference (Game.class, 2L); Player player1 = entitásManager.find (Player.class, 1L); player1.setGame (game2); entitásManager.persist (player1); 

Remélhetőleg a teszt futtatása megadja a várt viselkedést:

Hibernálás: válassza a player0_.id nevet id1_1_0_, player0_.game_id mint game_id3_1_0_, player0_.name nevet2_1_0_, game1_.id mint id1_0_1_, game1_.name nevet2_0_1_ a Player player0_ bal külsõ csatlakozáshoz Game game1_ on player0_.game_id = game1 .id =? Hibernálás: Frissítse a lejátszót a game_id = ?, name =? ahol id =? 

És látjuk, A hibernált állapot nem hajtja végre a SELECT lekérdezése a Játszma, meccs entitás, amikor használjuk getReference () ezúttal.

Szóval jó gyakorlatnak tűnik választani getReference () ebben az esetben. Ez azért van, mert egy meghatalmazott Játszma, meccs entitás elegendő a kapcsolat létrehozásához a Játékos entitás - az Játszma, meccs az entitást nem kell inicializálni.

Következésképpen, felhasználásával getReference () kiküszöböli az adatbázisunk felesleges körútjait, amikor frissítjük az entitáskapcsolatokat.

5. Hibernált első szintű gyorsítótár

Néha zavaró lehet mindkét módszer megtalálja() és getReference () nem hajthat végre semmit SELECT lekérdezések bizonyos esetekben.

Képzeljünk el egy olyan helyzetet, amikor entitásaink már a működésünk előtti perzisztencia-környezetben vannak betöltve:

entitásManager.getTransaction (). begin (); entitManager.persist (új játék (1L, "1. játék")); entitManager.persist (új játékos (1L, "1. játékos")); entitásManager.getTransaction (). kötelezettség (); entitásManager.getTransaction (). begin (); Game game1 = entitásManager.getReference (Game.class, 1L); Player player1 = entitásManager.find (Player.class, 1L); player1.setGame (game1); entitásManager.persist (player1); entitásManager.getTransaction (). kötelezettség (); 

A teszt futtatása azt mutatja, hogy csak a frissítési lekérdezést hajtották végre:

Hibernálás: Frissítse a lejátszót a game_id = ?, name =? ahol id =? 

Ilyen esetben ezt észre kell vennünk nem látunk ilyet SELECT lekérdezések, használjuk-e megtalálja() vagy getReference (). Ennek oka az, hogy entitásaink a Hibernate első szintű gyorsítótárában vannak tárolva.

Ennek eredményeként amikor entitásaink a Hibernate első szintű gyorsítótárában vannak tárolva, akkor mindkettő megtalálja() és getReference () A módszerek azonosak és nem ütik meg az adatbázisunkat.

6. Különböző KPK-megvalósítások

Utolsó emlékeztetőként tisztában kell lennünk azzal, hogy a getReference () módszer a mögöttes perzisztencia szolgáltatótól függ.

A JPA 2 specifikációja szerint a kitartásszolgáltatónak megengedett a dobása EntityNotFoundException amikor az getReference () módszert nevezzük. Így más lehet a perzisztencia-szolgáltatók esetében, és találkozhatunk velük EntityNotFoundException amikor használjuk getReference ().

Mindazonáltal, A hibernált állapot nem követi a getReference () alapértelmezés szerint, ha lehetséges, menteni kell egy adatbázis-kört. Ennek megfelelően nem vet ki kivételt, ha lekérdezzük az entitás-proxykat, még akkor is, ha nem léteznek az adatbázisban.

Alternatív megoldásként A hibernálás olyan konfigurációs tulajdonságot kínál, amely véleményezett módon kínál lehetőséget azok számára, akik szeretnék betartani a JPA specifikációt.

Ilyen esetben fontolóra vehetjük a hibernate.jpa.compliance.proxy tulajdonhoz igaz:

Ezzel a beállítással a Hibernate mindenképpen inicializálja az entitás proxyt, ami azt jelenti, hogy végrehajtja a SELECT lekérdezés akkor is, ha használjuk getReference ().

7. Következtetés

Ebben az oktatóanyagban néhány olyan felhasználási esetet tártunk fel, amelyek hasznosak lehetnek a referencia proxy objektumok számára, és megtanultuk a használatukat EntityManager’S getReference () módszer hibernált állapotban.

Mint mindig, az oktatóanyag összes kódmintája és további tesztesetei elérhetők a GitHubon.