A Hibernate és a JPA

a sok-sok asszociációk az egyik leggyakrabban használt asszociáció a JPA és a Hibernate esetén. Rengeteg példát találhatsz rájuk a valós világban, és leképezheted őket a JPA – val és a Hibernate-tel egy-vagy kétirányú asszociációként a domain modelledben.

de valószínűleg azt is tudja, hogy ezek a leképezések számos buktatót nyújtanak. Ebben a cikkben 5 legjobb gyakorlatot mutatok be, amelyek segítenek elkerülni ezeket a buktatókat és hatékony leképezéseket végrehajtani. Meg fogja tanulni:

  1. a Társítás leghatékonyabb adattípusa
  2. miért van szükség segédprogramokra az Társítás kezeléséhez
  3. a megfelelő FetchType a hatékony leképezéshez
  4. mikor és hogyan kell használni a lekérdezés-specifikus leképezést
  5. a CascadeType-ot, amelyet minden áron el kell kerülnie

nem fogok belemerülni egy alapvető sok-sok leképezés részleteibe. Ha nem biztos abban, hogyan lehet ilyen leképezést létrehozni, kérjük, vessen egy pillantást az asszociációs leképezési útmutatóm sok-sok szakaszára.

a Társítás leghatékonyabb adattípusa

YouTube videó

a legtöbb fejlesztő nem sok gondolatot költ egy to-many Társítás adattípusára. Csak egy java-t választanak.util.Lista, mert egyszerű, és nem végez ellenőrzéseket a duplikációk elkerülése érdekében.

Ez rendben van, ha egy alapvető Java osztályt implementál, vagy ha EGY-a-sokhoz/sok-az-egyhez társítást modellez. De soha ne használjon listát, ha sok-sok társítást modellez.

@Entitypublic class Book {// DON'T DO THIS!!!@ManyToMany@JoinTable(name = "book_author", joinColumns = { @JoinColumn(name = "fk_book") }, inverseJoinColumns = { @JoinColumn(name = "fk_author") })private List<Author> authors = new ArrayList<Author>();...}

a hibernált fogantyúk eltávolítják a java-hoz leképezett sok-sok kapcsolat műveleteit.util.A lista nagyon nem hatékony.

em = emf.createEntityManager();em.getTransaction().begin();// Get Book entity with 2 Authorsb = em.find(Book.class, 1L);// Remove one of the Authorb.getAuthors().remove(a);em.getTransaction().commit();em.close();

először eltávolítja az összes rekordot az asszociációs táblából, mielőtt beszúrja az összes maradékot.

09:54:28,876 DEBUG - update Book set title=?, version=? where id=? and version=?09:54:28,878 DEBUG - delete from book_author where fk_book=?09:54:28,882 DEBUG - insert into book_author (fk_book, fk_author) values (?, ?)

ehelyett egy sok-sok társítást kell java-ként modelleznie.util.Kész.

@Entitypublic class Book {@ManyToMany@JoinTable(name = "book_author", joinColumns = { @JoinColumn(name = "fk_book") }, inverseJoinColumns = { @JoinColumn(name = "fk_author") })private Set<Author> authors = new HashSet<Author>();...}

hibernálás, majd kezeli eltávolítani műveletek az egyesület sokkal jobb. Most már csak a várt rekordokat távolítja el az Egyesületből, a többieket pedig érintetlenül tartja.

10:00:37,709 DEBUG - update Book set title=?, version=? where id=? and version=?10:00:37,711 DEBUG - delete from book_author where fk_book=? and fk_author=?

miért van szükség segédprogramokra az asszociáció kezeléséhez?

a kétirányú asszociációk egy entitás attribútumhoz vannak hozzárendelve a kapcsolatok mindkét végén. Tehát az előző példában van egy szerzők attribútum a könyv entitáson, és egy könyvek attribútum a szerző entitáson. Ez nagyon kényelmessé teszi a JPQL vagy a CriteriaQuery megvalósítását, mert ezeket az attribútumokat használhatja egy csatlakozási záradék meghatározására.

de egy Társítás hozzáadása vagy eltávolítása bonyolultabbá válik. Mindig el kell végeznie a változást az egyesület mindkét végén. Ha például könyvet szeretne hozzáadni a szerzőhöz, akkor azt hozzá kell adnia a szerző entitás könyvek attribútumához, valamint hozzá kell adnia a szerző a szerzők attribútumot a könyv entitáshoz. Ellenkező esetben a jelenlegi perzisztencia kontextus inkonzisztens adatokat tartalmaz, amelyeket a jelenlegi tranzakció végéig használ.

Book b = new Book();b.setTitle("Hibernate Tips - More than 70 solutions to common Hibernate problems");em.persist(b);Author a = em.find(Author.class, 1L);a.getBooks().add(b);b.getAuthors().add(a);

a szerző és a könyv entitások segédprogramjai sokkal könnyebbé teszik a frissítést és az eltávolítást. Ezeken a módszereken belül mindkét entitáson végrehajtja a szükséges műveleteket.

@Entitypublic class Author {@ManyToMany(mappedBy = "authors")private Set<Book> books = new HashSet<Book>();...public void addBook(Book book) {this.books.add(book);book.getAuthors().add(this);}public void removeBook(Book book) {this.books.remove(book);book.getAuthors().remove(this);}}

A megfelelő FetchType a hatékony leképezéshez

YouTube videó

Ez egy gyors. Mindig használja FetchType.Lusta a sok-sok egyesület számára. Azt mondja a perzisztencia szolgáltatónak, hogy addig ne töltse le a társított entitásokat az adatbázisból, amíg nem használja őket. Ez általában akkor fordul elő, amikor először hívja meg getter módszerét.

szerencsére, ez az alapértelmezett Minden To-sok egyesület. Ezért kérjük, győződjön meg róla, hogy nem változtatja meg.

és ha többet szeretne megtudni a JPA különböző FetchTypes-jeiről, kérjük, nézze meg a JPA FetchTypes Bevezetőmet.

mikor és hogyan kell használni a lekérdezés-specifikus lekérést

Ha FetchType-t használ.Lusta, tudnia kell a lekérdezés-specifikus lekérésről. Ellenkező esetben az alkalmazás nagyon lassú lesz, mert sok n+1 select problémát hozott létre.

YouTube videó

amikor betölt egy entitást és lekérdezés-specifikus lekérést használ, megmondja a Hibernate-nek, hogy mely leképezett asszociációkat inicializálja az egyes lekérett entitásokhoz. Ezután kiterjeszti a lekérdezés SELECT záradékát úgy, hogy tartalmazza az ezen entitások által leképezett oszlopokat, és inicializálja az asszociációkat. Mivel a társítások már inicializálva vannak, a Hibernate-nek nem kell további lekérdezést végrehajtania, amikor először lép be a getter metódusába.

a lekérdezés-specifikus lekérést többféle módon valósíthatja meg. A legegyszerűbb egy JOIN FETCH záradék, amelyet itt mutatok meg. De használhat egy @NamedEntityGraph-ot vagy egy EntityGraph-ot is, amelyet a korábbi cikkekben kifejtettem.

a JOIN FETCH záradék meghatározása majdnem megegyezik a jpql lekérdezés egyszerű JOIN záradékával. Csak hozzá kell adnia a FETCH kulcsszót.

Author a = em.createQuery("SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = 1", Author.class).getSingleResult();

ennek ellenére a JOIN és a JOIN FETCH záradék nagyon hasonlít, a JOIN FETCH záradék sokkal nagyobb hatással van a generált SQL lekérdezésre. Ez nem csak lesz lefordítva SQL JOIN, mint ez a helyzet a JPQL JOIN záradék, azt is kényszeríti a perzisztencia szolgáltató kiterjeszteni a SELECT záradék minden oszlopot, amely leképezi a társított entitás.

16:21:03,046 DEBUG SQL:94 - select author0_.id as id1_0_0_, book2_.id as id1_1_1_, author0_.firstName as firstNam2_0_0_, author0_.lastName as lastName3_0_0_, author0_.version as version4_0_0_, book2_.format as format2_1_1_, book2_.publishingDate as publishi3_1_1_, book2_.title as title4_1_1_, book2_.version as version5_1_1_, books1_.author_id as author_i2_2_0__, books1_.book_id as book_id1_2_0__ from Author author0_ inner join book_author books1_ on author0_.id=books1_.author_id inner join Book book2_ on books1_.book_id=book2_.id where author0_.id=1

A CascadeType, amelyet minden áron el kell kerülnie

ha a cascading funkciót egy társításon aktiválja, a perzisztencia szolgáltató az entitáson végrehajtott műveleteket az összes társított entitásra alkalmazza. Ha ez nem, hogy az összes műveletet, vagy csak néhány kiválasztott is függ a konfigurált CascadeType.

YouTube videó

Ez egy csodálatos ötletnek tűnhet, amely sokkal könnyebbé teszi az üzleti logika megvalósítását. És ez nem teljesen rossz.

de kérjük, kerülje a CascadeTypes REMOVE and ALL-t, amely magában foglalja az eltávolítást is, a sok-sok asszociációhoz. A legjobb esetben csak teljesítményproblémákat okoz, de a legrosszabb esetben több rekordot is eltávolíthat, mint amennyit tervezett.

egy korábbi cikkben részletesen elmagyaráztam mind a buktatókat, mind a megoldásukat. Vagy ha egyszerűen szeretné tartani, indítsa el a szükséges információkat programszerűen a társított entitásokon. Ehhez szükség lehet még néhány sornyi kódra, de elkerüli a váratlan mellékhatásokat.

következtetés

rengeteg példát találhatsz a sok-sok asszociációra a Való Világban, és könnyen feltérképezheted őket a JPA és a Hibernate segítségével. Sajnos ezek az egyszerű leképezések elrejtenek néhány buktatót, amelyeket elkerülhet az alábbi 5 legjobb gyakorlat követésével:

  1. modell asszociációk java-ként.util.Kész.
  2. adjon meg segédprogramokat egy entitás hozzáadásához vagy eltávolításához egy társításból.
  3. mindig használja FetchType.Lusta, ami az alapértelmezett, a teljesítményproblémák elkerülése érdekében.
  4. lekérdezés-specifikus Lekérés alkalmazása az n+1 select problémák elkerülése érdekében.
  5. ne használja a CASCADETYPES REMOVE-ot és mindent.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.