a JPA és a Hibernate különböző módszereket biztosít az új elemek fennmaradásához és a meglévő entitások frissítéséhez. Választhat a JPA persist és merge, valamint a Hibernate mentési és frissítési módszerei között.
úgy tűnik, hogy 2 pár 2 módszer van, amelyek ugyanezt teszik. A persistine és a save metódusok segítségével új entitást tárolhat, a merge és update metódusokkal pedig egy leválasztott entitás módosításait tárolhatja az adatbázisban. Ezért sok fejlesztő kíváncsi arra, hogy ezek közül a módszerek közül melyiket kell használni. Vessünk egy közelebbi pillantást ezeknek a módszereknek a részleteire és kis különbségeire.
Külön köszönet Steve Ebersole – nak (vezető fejlesztő-Hibernate ORM), aki visszajelzést és nagyszerű betekintést nyújtott a Hibernate rejtett implementációs részleteiről!
- entitás állapot átmenetek
- új entitás megmaradása a persist vagy save
- specifikáció vs. Szabadalmaztatott API
- visszatérési típusok és SQL utasítások végrehajtása
- nem generált
- Táblastratégiával létrehozva
- melyiket válasszuk?
- leválasztott entitás frissítése
- a JPA egyesítési módszere
- Hibernate frissítési módszere
- melyiket válasszuk?
- felügyelt entitás frissítése
entitás állapot átmenetek
mielőtt belemennénk a 4 módszer részleteibe, gyors bevezetést kell adnom a JPA entitás életciklus-állapotaihoz.
ha egy entitás kapcsolódik az aktuális perzisztencia környezethez, akkor az életciklus állapotát kezeli. Ez azt jelenti, hogy egy adatbázis-rekordhoz van hozzárendelve. A perzisztencia szolgáltató generálja a szükséges SQL INSERT and UPDATE utasításokat az összes változás terjesztéséhez. A felügyelt entitás az 1. szintű gyorsítótárban is tárolódik.
amikor új entitást hoz létre, az átmeneti állapotban van. Ebben az állapotban marad, amíg nem csatolja az aktuális perzisztencia kontextushoz. A következő részben megmutatom, hogyan lehet ezt megtenni a JPA persist és a Hibernate mentési módszerével. Mindaddig, amíg egy entitás tranziens állapotban van, nem kapcsolódik adatbázis-rekordhoz, és nem kezeli semmilyen perzisztencia-környezet.
a leválasztott életciklus-állapotban lévő entitásokat már nem kezeli a perzisztencia környezet. Ez azért fordulhat elő, mert bezárta a perzisztencia kontextust, vagy kifejezetten leválasztotta az entitást az aktuális kontextustól. A bejegyzés egy későbbi részében további részleteket fogok megtudni arról, hogyan lehet ezeket az entitásokat újra összekapcsolni a JPA merge és Hibernate frissítési módszereivel.
és az utolsó életciklus állapot törlődik. Ezek az entitások korábban a kezelt állapotban voltak, mielőtt ütemezte őket eltávolításra. Az entitások eltávolítása kívül esik a bejegyzés hatókörén, ezért nem fogok túl sok részletbe belemenni. Az entitás eltávolítását az EntityManager felületen található eltávolítási módszer meghívásával ütemezheti.
új entitás megmaradása a persist vagy save
használatával új entitásobjektum létrehozásakor az átmeneti életciklus állapotban van. Ez nem Térkép semmilyen adatbázis rekordot.
Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");
csatolnia kell az entitást egy perzisztencia környezethez, hogy felügyelhetővé váljon, és megmaradjon az adatbázisban. Ehhez használhatja a JPA persist vagy a Hibernate mentési módszerét. Úgy tűnik, hogy mindkét módszer ugyanazt teszi, de van néhány különbség.
specifikáció vs. Szabadalmaztatott API
a legnyilvánvalóbb különbség az, hogy a JPA specifikáció meghatározza a persist metódust. Használhatja az összes JPA implementációval. A mentési módszer viszont hibernált-specifikus. Ezért nem érhető el más JPA implementációkban.
de ez csak akkor releváns, ha azt szeretné, hogy a Hibernate egy másik JPA megvalósítással helyettesíthető legyen, mint például az Eclipse Link vagy az OpenJPA.
visszatérési típusok és SQL utasítások végrehajtása
egy másik nyilvánvaló különbség a 2 módszer között a visszatérési típusuk. A JPA persist metódusa érvénytelen, a Hibernate mentési metódusa pedig az entitás elsődleges kulcsát adja vissza.
ez hatalmas különbségnek tűnhet, különösen, ha közelebbről megnézzük a Hibernate Javadoc-ját és a JPA specifikációját:
- a Hibernate mentési módszerének Javadoc-ja kimondja, hogy először az elsődleges kulcs értékét generálja:
tartsa fenn az adott átmeneti példányt, először hozzárendel egy generált azonosítót.
Javadoc Munkamenet.Mentés (entitás) - erről nem talál információt a JPA specifikációban. Nem határozza meg, hogy mikor kell hozzárendelni az elsődleges kulcs értékét. Tehát a perzisztencia szolgáltató ezt bármikor megteheti a persist metódus hívása és a perzisztencia kontextus öblítése között.
a legtöbb esetben nincs különbség, ha a Mentés vagy a fennmaradás módszert hívja. A Hibernate az entitás osztály nevét és az elsődleges kulcs értékét használja az entitás első szintű gyorsítótárban való tárolásához. Ezért elsődleges kulcsértékre van szüksége, amikor végrehajtja a persist metódust.
szinte minden helyzetben a Hibernate azonnal generálja az elsődleges kulcs értékét, és szükség esetén SQL utasítást indít, amikor meghívja a persist or save metódust.
de nem ez a helyzet, ha az IDENTITÁSSTRATÉGIÁT használja, és megpróbál fennmaradni egy entitás aktív tranzakció nélkül vagy FlushMode használatával.Kézi. Ha a persist metódust hívja meg ezen helyzetek egyikében, a Hibernate késlelteti az SQL INSERT utasítás végrehajtását, és ideiglenes elsődleges kulcsértéket hoz létre. Ha azonban a save metódust hívja, a Hibernate azonnal végrehajtja az SQL INSERT utasítást, és lekéri az elsődleges kulcs értékét az adatbázisból.
ezután visszakeresheti a mentési módszer visszatérési értékeként.
Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");Long id = (Long) em.unwrap(Session.class).save(a);
vagy meghívhatja a kezelt entitás elsődleges kulcsattribútumának getter metódusát, ha a JPA persist metódusát használja.
Author a = new Author();a.setFirstName("Torben");a.setLastName("Janssen");em.persist(a);Long id = a.getId();
a Hibernate ugyanazokat az SQL utasításokat hajtja végre, amikor a persist vagy a save metódust hívja. Melyik és mikor történik, az az elsődleges kulcsgenerációs stratégiától függ:
nem generált
ha az elsődleges kulcs értékét programozottan állítja be, például egy természetes azonosítóra, a Hibernate csak akkor hajt végre SQL INSERT utasítást, amikor az átöblíti a perzisztencia környezetet.
14:08:34,979 INFO TestPersistSaveMerge:237 - Save entity14:08:35,052 INFO TestPersistSaveMerge:240 - Commit transaction14:08:35,123 DEBUG SQL:92 - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?)
IDENTITÁSSTRATÉGIÁVAL létrehozva ha az IDENTITÁSSTRATÉGIÁT használja az elsődleges kulcs értékének létrehozásához, a Hibernate-nek végre kell hajtania az INSERT utasítást, amikor meghívja a save vagy persist metódust az elsődleges kulcs értékének az adatbázisból történő lekéréséhez.
14:09:28,264 INFO TestPersistSaveMerge:237 - Save entity14:09:28,336 DEBUG SQL:92 - insert into Author (firstName, lastName, version) values (?, ?, ?)14:09:28,354 INFO TestPersistSaveMerge:240 - Commit transaction
SZEKVENCIASTRATÉGIÁVAL generálva, és ha a szekvenciát használja, a Hibernate egy SQL SELECT utasítást hajt végre, hogy lekérje a következő értéket az adatbázis-szekvenciából. A hibernálás ezután késlelteti az INSERT utasítást, amíg ki nem öblíti a perzisztencia kontextust. Ebben a példában a flush akkor történik, amikor a tranzakció elköteleződik.
14:10:27,994 INFO TestPersistSaveMerge:237 - Save entity14:10:28,002 DEBUG SQL:92 - select nextval ('hibernate_sequence')14:10:28,042 INFO TestPersistSaveMerge:240 - Commit transaction14:10:28,096 DEBUG SQL:92 - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?)
Táblastratégiával létrehozva
nem szabad használni a TÁBLASTRATÉGIÁT, mert sorszintű zárolást igényel az elsődleges kulcstáblán, és nem méretezhető jól. Ha ezt a stratégiát egyébként is használja, a Hibernate végrehajtja az SQL SELECT utasítást a következő elsődleges kulcsérték lekéréséhez az adatbázisból, és az új értéket írja az adatbázis táblába. Késlelteti az új entitás SQL INSERT utasításának végrehajtását, amíg ki nem öblíti a perzisztencia kontextust.
14:11:17,368 INFO TestPersistSaveMerge:237 - Save entity14:11:17,482 DEBUG SQL:92 - select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update of tbl14:11:17,531 DEBUG SQL:92 - insert into hibernate_sequences (sequence_name, next_val) values (?,?)14:11:17,534 DEBUG SQL:92 - update hibernate_sequences set next_val=? where next_val=? and sequence_name=?14:11:17,584 INFO TestPersistSaveMerge:240 - Commit transaction14:11:17,655 DEBUG SQL:92 - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?)
melyiket válasszuk?
várható, hogy a save and persist metódus másképp viselkedik, mert van néhány különbség a JPA specifikáció és a Hibernate saját fejlesztésű módszereinek Javadoc-ja között.
de szinte ezek a különbségek eltűnnek, ha megnézzük a belső megvalósítást. Csak 2 sarok eset maradt meg, amikor a Hibernate késleltetheti az elsődleges kulcs visszakeresését, a metódus visszatérési típusát és más JPA implementációk támogatását.
a legtöbb alkalmazás esetében nincs különbség, ha a generált elsődleges kulcs értékét a Hibernate mentési módszerének visszatérési típusaként vagy az elsődleges kulcs attribútum getter módszeréből kapja. Mindaddig, amíg nem használ kiterjesztett perzisztencia kontextust, és minden adatbázis-műveletet aktív tranzakcióval hajt végre, javaslom a JPA persist metódusának használatát.
leválasztott entitás frissítése
amikor bezárja az aktuális perzisztencia környezetet, vagy explicit módon eltávolít belőle egy entitást az EntityManager felületen lévő Törlés vagy Leválasztás metódusok meghívásával, az entitás leválasztásra kerül. Ez azt jelenti, hogy már nem tárolja az 1.szintű gyorsítótárban, és a Hibernate nem replikálja az adatbázis alkalmazott módosításait.
a Hibernate frissítésével vagy a JPA egyesítési módszerével társíthat egy leválasztott entitást egy perzisztencia környezethez. Miután ezt megtette, a Hibernate frissíti az adatbázist az entitás attribútumértékei alapján.
úgy tűnik, hogy a frissítés és az egyesítés módszerének hatása ugyanaz, de amint azt a következő szakaszokban láthatja, van egy fontos különbség.
a JPA egyesítési módszere
a JPA egyesítési módszere átmásolja a leválasztott entitás állapotát ugyanazon entitás felügyelt példányára. A Hibernate ezért egy SQL SELECT utasítást hajt végre egy felügyelt entitás lekéréséhez az adatbázisból. Ha a perzisztencia környezet már tartalmazta az entitás felügyelt példányát, a Hibernate a meglévőt használja helyette. Ezután átmásolja az összes attribútumértéket a felügyelt entitásnak, és visszaadja a hívónak.
Author managedAuthor = em.merge(a);
az SQL utasítások naplózásának aktiválása után láthatja a végrehajtott SELECT and UPDATE utasításokat a napló kimenetén.
11:37:21,172 DEBUG SQL:92 - select books0_.bookId as bookId1_2_0_, books0_.authorId as authorId2_2_0_, book1_.id as id1_1_1_, book1_.fk_author as fk_autho6_1_1_, book1_.format as format2_1_1_, book1_.publishingDate as publishi3_1_1_, book1_.title as title4_1_1_, book1_.version as version5_1_1_, author2_.id as id1_0_2_, author2_.firstName as firstNam2_0_2_, author2_.lastName as lastName3_0_2_, author2_.version as version4_0_2_ from BookAuthor books0_ inner join Book book1_ on books0_.authorId=book1_.id left outer join Author author2_ on book1_.fk_author=author2_.id where books0_.bookId=?11:37:21,180 INFO TestPersistSaveMerge:82 - Before commit11:37:21,182 DEBUG SQL:92 - update Author set firstName=?, lastName=?, version=? where id=? and version=?
amikor a Hibernate a következő alkalommal átöblíti a perzisztencia környezetet, a piszkos ellenőrző mechanizmusa ellenőrzi az összes felügyelt entitást. Ha azt észleli, hogy az egyesítési művelet megváltoztatta az entitásattribútum értékét, elindítja a szükséges SQL UPDATE utasítást.
van egy fontos részlet, amelyet tudnia kell, amikor a JPA egyesítési módszerét használja. A Hibernate átmásolja a leválasztott entitás attribútumértékeit a felügyelt entitásra. Ez felülírja az entitáson az aktuális munkameneten belül végrehajtott módosításokat.
Hibernate frissítési módszere
a Hibernate frissítési módszere nem indít SQL SELECT utasítást. Csak az entitást a jelenlegi perzisztencia kontextushoz kapcsolja. A JPA egyesítési módszerével ellentétben a frissítési módszer meghívásával nem veszíthet el semmilyen változást. Ha a perzisztencia környezet már tartalmazza a frissíteni kívánt entitás felügyelt példányát, kivételt dob.
em.unwrap(Session.class).update(a);
amikor a Hibernate elvégzi a következő öblítést, nem végez piszkos ellenőrzéseket. Ez nem lehetséges, mert a Hibernate nem olvasta az entitás legújabb verzióját az adatbázisból. Csak végrehajtja az SQL UPDATE utasítást az újracsatolt entitás számára.
11:38:28,151 INFO TestPersistSaveMerge:121 - Before commit11:38:28,153 DEBUG SQL:92 - update Author set firstName=?, lastName=?, version=? where id=? and version=?
a hiányzó piszkos ellenőrzés szükségtelen SQL UPDATE utasítást okoz, ha az entitás és a megfelelő adatbázis rekord ugyanazokat az értékeket tartalmazza. Ez problémát jelenthet, ha a DBA regisztrált egy frissítési triggert az adatbázis táblához. Ilyen esetekben az entitást a @SelectBeforeUpdate segítségével jegyezheti fel.
@Entity@SelectBeforeUpdatepublic class Author { ... }
ez azt mondja a Hibernate-nek, hogy válassza ki az entitást, és végezzen piszkos ellenőrzést, mielőtt létrehozza az SQL UPDATE utasítást. Amint a napló kimenetén látható, a frissítési módszer viselkedése most hasonló a JPA egyesítési módszeréhez.
19:08:16,530 INFO TestPersistSaveMerge:121 - Before commit19:08:16,531 DEBUG SQL:92 - select author_.id, author_.firstName as firstNam2_0_, author_.lastName as lastName3_0_, author_.version as version4_0_ from Author author_ where author_.id=?19:08:16,592 DEBUG SQL:92 - update Author set firstName=?, lastName=?, version=? where id=? and version=?
de jelentős különbség van a 2 módszer között. A frissítési módszer meghívásakor a Hibernate csak azt az entitást választja ki, amelyet metódusparaméterként adott meg. De amikor felhívja a JPA egyesítési módszerét, a Hibernate a CascadeType összes társítását is kiválasztja.Egyesülés. Ezért előnyben kell részesítenie a JPA egyesítési módszerét, ha egy hatalmas entitásgráfot csatol vissza.
melyiket válasszuk?
erre a kérdésre nincs általános válasz. Mint láttuk, mindkét módszernek megvannak az előnyei és hátrányai. El kell döntenie az adott használati esetről, ha a Hibernate-nek ki kell választania az entitást, mielőtt kiváltja az SQL UPDATE utasítást. És ha ez a helyzet, akkor figyelembe kell vennie az entitásgráf mélységét és a megadott lekérési viselkedés teljesítménybeli következményeit is.
felügyelt entitás frissítése
a JPA és a hibernálás nagyon egyszerűvé teszi a felügyelt entitás frissítését. Ha az entitás a kezelt életciklus állapotban van, például azért, mert JPQL lekérdezéssel vagy az EntityManager find metódusával töltötte be, akkor csak módosítania kell az entitás attribútumainak értékeit.
em = emf.createEntityManager();em.getTransaction().begin();a = em.find(Author.class, a.getId());a.setFirstName("Thorben");log.info("Before commit");em.getTransaction().commit();em.close();
amikor a Hibernate úgy dönt, hogy törli a perzisztencia környezetét, a dirty checking mechanizmus észleli a változást, és végrehajtja a szükséges SQL UPDATE utasítást.
11:41:49,178 DEBUG SQL:92 - select author0_.id as id1_0_0_, author0_.firstName as firstNam2_0_0_, author0_.lastName as lastName3_0_0_, author0_.version as version4_0_0_ from Author author0_ where author0_.id=?11:41:49,191 INFO TestPersistSaveMerge:335 - Before commit11:41:49,193 DEBUG SQL:92 - update Author set firstName=?, lastName=?, version=? where id=? and version=?
Nem szükséges, és nem szabad meghívni a Hibernate mentési módszerét az entitás frissítése után. Ez további SaveOrUpdate eseményt indít el anélkül, hogy bármilyen előnyt biztosítana. Amikor a Hibernate úgy dönt, hogy öblíti a perzisztencia kontextust, akkor mindenképpen elvégzi a piszkos ellenőrzést, hogy észlelje az összes változást, mielőtt végrehajtja a szükséges SQL frissítési utasításokat.