Munka a Lazy Element Gyűjteményekkel a JPA-ban
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT1. Áttekintés
A JPA specifikációja két különböző lekérési stratégiát tartalmaz: lelkes és lusta. Míg a lusta megközelítés segít elkerülni a szükségtelen adatok felesleges betöltését, olykor olyan adatokat kell olvasnunk, amelyeket eredetileg nem zárt perzisztencia-kontextusban töltöttünk be. Ezenkívül gyakori probléma a lusta elemgyűjteményekhez való hozzáférés zárt perzisztencia-kontextusban.
Ebben az oktatóanyagban arra összpontosítunk, hogyan töltsön be adatokat a lusta elemgyűjteményekből. Három különböző megoldást fogunk felfedezni: az egyik a JPA lekérdezési nyelvet foglalja magában, a másik az entitásdiagramok használatával, az utolsó pedig a tranzakcióterjesztéssel.
2. Az elemgyűjtési probléma
Alapértelmezés szerint a JPA a lusta letöltési stratégiát használja típusú társításokban @ElementCollection. Így a gyűjteményhez való hozzáférés zárt perzisztencia-környezetben kivételt eredményez.
A probléma megértése érdekében definiáljunk egy tartományi modellt az alkalmazott és a telefonlista közötti kapcsolat alapján:
@Entity public class Alkalmazott {@Id private int id; privát karakterlánc neve; @ElementCollection @CollectionTable (név = "alkalmazott_telefon", joinColumns = @JoinColumn (név = "alkalmazott_azonosító")) magánlista telefonok; // szabványos kivitelezők, mérőeszközök és beállítók} @Embeddable public class Phone {private String type; privát String areaCode; privát karakterlánc száma; // szabványos kivitelezők, mérőeszközök és beállítók}
Modellünk meghatározza, hogy egy alkalmazottnak sok telefonja lehet. A telefonlista a beágyazható típusok gyűjteménye. Használjunk egy tavaszi adattárat ezzel a modellel:
@Repository public class EmployeeRepository {public Employee findById (int id) {return em.find (Employee.class, id); } // további tulajdonságok és kiegészítő módszerek}
Most ismételjük meg a problémát egy egyszerű JUnit tesztesettel:
public class ElementCollectionIntegrationTest {@Before public void init () előtt {Employee alkalmazott = új alkalmazott (1, "Fred"); worker.setPhones (Arrays.asList (új telefon ("munka", "+55", "99999-9999"), új telefon ("otthon", "+55", "98888-8888"))); workerRepository.save (alkalmazott); } @A nyilvános void után clean () {workerRepository.remove (1); } @Test (várható = org.hibernate.LazyInitializationException.class) public void whenAccessLazyCollection_thenThrowLazyInitializationException () {Employee alkalmazott = alkalmazottRepository.findById (1); assertThat (alkalmazott.getPhones (). méret (), az (2)); }}
Ez a teszt kivételt hoz, amikor megpróbálunk hozzáférni a telefonlistához, mert a Perzisztencia kontextus zárva van.
Megoldhatjuk ezt a problémát a. letöltési stratégiájának megváltoztatása @ElementCollection hogy a lelkes megközelítést alkalmazza. Azonban lelkesen beolvasni az adatokat nem feltétlenül a legjobb megoldás, mivel a telefonadatok mindig betöltődnek, akár szükségünk van rá, akár nem.
3. Adatok betöltése a JPA lekérdezési nyelvvel
A JPA lekérdezési nyelve lehetővé teszi számunkra a kivetített információk testreszabását. Ezért meghatározhatunk egy új módszert a EmployeeRosory az alkalmazott és telefonjainak kiválasztásához:
public Employee findByJPQL (int id) {return em.createQuery ("SELECT u FROM Employee AS u JOIN FETCH u.phones WHERE u.id =: id", Employee.class) .setParameter ("id", id) .getSingleResult ( ); }
A fenti lekérdezés belső csatlakozási műveletet használ a telefonlista lekéréséhez minden visszatért alkalmazottért.
4. Adatok betöltése entitásgráffal
Egy másik lehetséges megoldás a JPA entitásdiagram szolgáltatásának használata. Az entitásdiagram lehetővé teszi számunkra, hogy kiválasszuk, mely mezőket vetítik ki a JPA-lekérdezések. Határozzunk meg még egy módszert a tárunkban:
public Employee findByEntityGraph (int id) {EntityGraph entityGraph = em.createEntityGraph (Employee.class); entityGraph.addAttributeNodes ("név", "telefonok"); Térkép tulajdonságai = új HashMap (); tulajdonságok.put ("javax.persistence.fetchgraph", entitGraph); return em.find (Munkavállaló.osztály, azonosító, tulajdonságok); }
Ezt láthatjuk entitás grafikonunk két attribútumot tartalmaz: nevet és telefonokat. Tehát, amikor a JPA ezt SQL-re fordítja, kivetíti a kapcsolódó oszlopokat.
5. Adatok betöltése egy ügyleti körbe
Végül egy utolsó megoldást fogunk feltárni. Eddig azt láttuk, hogy a probléma a perzisztencia kontextus életciklusához kapcsolódik.
Az történik a perzisztencia-kontextusunk tranzakciókörű és nyitva marad, amíg a tranzakció befejeződik. A tranzakció életciklusa a repository módszer végrehajtásának elejétől a végéig tart.
Tehát hozzunk létre egy újabb tesztesetet, és állítsuk be a Perzisztencia-kontextust úgy, hogy a teszt módszerünkkel elindított tranzakcióhoz kapcsolódjon. A teszt végéig nyitva tartjuk a perzisztencia-kontextust:
@Test @Transactional public void whenUseTransaction_thenFetchResult () {Alkalmazott alkalmazott = alkalmazottRepository.findById (1); assertThat (alkalmazott.getPhones (). méret (), az (2)); }
A @ Tranzakció az annotáció egy tranzakciós proxyt konfigurál a kapcsolódó tesztosztály példánya köré. Sőt, a tranzakció társul a végrehajtó szálhoz. Figyelembe véve az alapértelmezett tranzakcióterjesztési beállítást, minden ezzel a módszerrel létrehozott Persistence Context csatlakozik ugyanahhoz a tranzakcióhoz. Következésképpen a tranzakció-perzisztencia összefüggései a vizsgálati módszer tranzakciós hatóköréhez vannak kötve.
6. Következtetés
Ebben az oktatóanyagban három különböző megoldást értékeltünk a lusta társulásoktól származó adatok zárt perzisztencia-kontextusban történő olvasásának problémájának kezelésére.
Először a JPA lekérdezési nyelvet használtuk az elemgyűjtemények lekéréséhez. Ezután meghatároztunk egy entitásdiagramot a szükséges adatok beolvasásához.
És a végső megoldásban a tavaszi tranzakciót használtuk arra, hogy nyitva tartsuk a perzisztencia kontextust, és elolvassuk a szükséges adatokat.
Mint mindig, az oktatóanyag példakódja elérhető a GitHubon.
Java alsó