JPA a hibernace poskytují různé metody pro přetrvávání nových a aktualizaci stávajících entit. Můžete si vybrat mezi způsoby ukládání a aktualizace JPA přetrvávat a sloučit a hibernace.
zdá se, že existují 2 páry 2 metod, které dělají totéž. Metody persist a save můžete použít k uložení nové entity a metody sloučit a aktualizovat k uložení změn oddělené entity v databázi. To je důvod, proč se mnoho vývojářů zajímá, která z těchto metod by měla používat. Podívejme se blíže na detaily a malé rozdíly těchto metod.
Zvláštní poděkování Steve Ebersole (vedoucí vývojář-Hibernate ORM), který poskytl svou zpětnou vazbu a skvělé poznatky o některých skrytých implementačních detailech Hibernate!
- přechody stavu entit
- přetrvávající Nová entita pomocí persist nebo save
- SPECIFIKACE vs. Proprietární API
- návratové typy a provádění příkazů SQL
- Není generován
- Generované IDENTITY strategie
- Generované SEKVENCE strategie
- generované se strategií tabulky
- který z nich si vybrat?
- Aktualizace oddělenou entitu
- metoda sloučení JPA
- metoda aktualizace hibernace
- který z nich si vybrat?
- aktualizace spravované entity
přechody stavu entit
než se dostaneme do podrobností o těchto metodách 4, musím vám rychle představit stavy životního cyklu entit JPA.
pokud je entita připojena k současnému kontextu persistence, má spravovaný stav životního cyklu. To znamená, že je mapován do databázového záznamu. Váš poskytovatel persistence generuje požadované příkazy SQL INSERT a UPDATE, aby propagoval všechny změny. Spravovaná entita je také uložena v mezipaměti 1. úrovně.
když vytvoříte novou entitu, je v přechodném stavu. Zůstává v tomto stavu, dokud jej nepřipojíte k současnému kontextu perzistence. Ukážu vám, jak to můžete udělat pomocí metody ukládání JPA přetrvávat a hibernace, v následující části. Pokud je entita v přechodném stavu, není mapována do databázového záznamu a není spravována žádným kontextem persistence.
entity v odděleném stavu životního cyklu již nejsou spravovány kontextem persistence. To může být případ, protože jste uzavřeli kontext persistence nebo jste entitu explicitně oddělili od aktuálního kontextu. Dostanu se do více podrobností o tom, jak můžete tyto entity znovu připojit pomocí metod JPA merge a Hibernate update v pozdější části tohoto příspěvku.
a poslední stav životního cyklu je odstraněn. Tyto subjekty byly dříve ve státě spravovány, než jste je naplánovali k odstranění. Odstranění entit je mimo rozsah tohoto příspěvku, takže se o něm nedostanu do příliš mnoha podrobností. Entitu pro odebrání můžete naplánovat voláním metody odebrat v rozhraní EntityManager.
přetrvávající Nová entita pomocí persist nebo save
když vytvoříte nový objekt entity, je ve stavu životního cyklu transient. To není mapovat žádný záznam databáze.
Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");
je třeba připojit entitu ke kontextu persistence, aby se spravovala a přetrvávala v databázi. K tomu můžete použít metodu uložení JPA nebo hibernace. Zdá se, že obě metody dělají totéž, ale existuje několik rozdílů.
SPECIFIKACE vs. Proprietární API
nejviditelnějším rozdílem je, že SPECIFIKACE JPA definuje metodu persist. Můžete jej použít se všemi implementacemi JPA. Metoda uložení je naproti tomu specifická pro režim hibernace. Proto není k dispozici v jiných implementacích JPA.
ale to je relevantní pouze v případě, že chcete být schopni nahradit Hibernate jinou implementací JPA, jako je Eclipse Link nebo OpenJPA.
dalším zřejmým rozdílem mezi těmito 2 metodami je jejich návratový typ. Metoda JPA persist vrací void a metoda Hibernate save vrací primární klíč entity.
To se může zdát jako velký rozdíl, zvlášť když jste se blíže podívat na Hibernate je Javadoc a SPS specifikace:
- Na Javadoc z Hibernace je uložit metoda státy, které to generuje hodnotu primárního klíče první:
Přetrvávají dané přechodné stupně, první přiřazení vygenerovaný identifikátor.
Relace Javadoc.uložit (entita) - ve specifikaci JPA o tom nenajdete žádné informace. Nedefinuje, kdy má být přiřazena hodnota primárního klíče. Poskytovatel persistence to tedy může udělat kdykoli mezi voláním metody persist a flush kontextu persistence.
ve většině případů nezáleží na tom, zda voláte metodu uložit nebo přetrvávat. Hibernace používá název třídy entity a hodnotu primárního klíče k uložení entity do mezipaměti první úrovně. Proto potřebuje hodnotu primárního klíče, když provádí metodu persist.
téměř ve všech situacích hibernace okamžitě vygeneruje hodnotu primárního klíče a v případě potřeby spustí příkaz SQL, když zavoláte metodu persist nebo save.
ale to není případ, pokud použijete strategii IDENTITY a pokusíte se přetrvávat entitu bez aktivní transakce nebo s FlushMode.PŘÍRUČKA. Pokud v jedné z těchto situací zavoláte metodu persist, režim hibernace zpozdí provedení příkazu SQL INSERT a vytvoří dočasnou hodnotu primárního klíče. Pokud však zavoláte metodu uložení, hibernace okamžitě provede příkaz SQL INSERT a načte hodnotu primárního klíče z databáze.
pak jej můžete načíst jako návratovou hodnotu metody uložení.
Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");Long id = (Long) em.unwrap(Session.class).save(a);
nebo můžete volat metodu getter atributu primárního klíče spravované entity, pokud používáte metodu JPA persist.
Author a = new Author();a.setFirstName("Torben");a.setLastName("Janssen");em.persist(a);Long id = a.getId();
hibernace provede stejné příkazy SQL při volání metody persist nebo save. Které a kdy to udělá, záleží na vaší strategii generování primárního klíče:
Není generován
Pokud nastavíte hodnotu primárního klíče programově, např. do přírodní identifikátor, Přezimují pouze provede SQL příkaz INSERT, když se to spláchne vytrvalost kontextu.
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 (?, ?, ?, ?)
Generované IDENTITY strategie
Pokud používáte IDENTITY strategie pro generování primárního klíče hodnotu, Přezimovat musí provést INSERT při volání uložit nebo přetrvávají metoda pro načtení hodnoty primárního klíče z databáze.
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
Generované SEKVENCE strategie
A pokud budete používat SEKVENCE, Hibernace, provede SQL příkaz SELECT k načtení další hodnoty z databáze sekvence. Hibernace pak odloží příkaz INSERT, dokud nevyplave kontext perzistence. V tomto příkladu se flush stane, když se transakce odevzdá.
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 (?, ?, ?, ?)
generované se strategií tabulky
neměli byste používat strategii tabulky, protože vyžaduje zámky na úrovni řádků v tabulce primárního klíče a není dobře škálovatelné. Pokud tuto strategii stejně použijete, hibernace provede příkaz SQL SELECT pro načtení další hodnoty primárního klíče z databáze a zapíše novou hodnotu do databázové tabulky. Zpožďuje spuštění příkazu SQL INSERT pro novou entitu, dokud nevyplave kontext persistence.
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 (?, ?, ?, ?)
který z nich si vybrat?
můžete očekávat, že ušetřit a přetrvávají metoda chovat jinak, protože existuje několik rozdílů mezi JPA specifikace a Javadoc z Hibernace je proprietární metody.
ale téměř všechny tyto rozdíly zmizí, když se podíváte na interní implementaci. Jediné, které zůstávají, jsou 2 rohové případy, ve kterých hibernace může zpozdit načítání primárního klíče, typ návratu metody a podporu jinými implementacemi JPA.
u většiny aplikací nezáleží na tom, zda získáte generovanou hodnotu primárního klíče jako návratový typ metody uložení hibernace nebo z metody getter vašeho atributu primárního klíče. Pokud nepoužíváte rozšířený kontext persistence a neprovádíte všechny databázové operace s aktivní transakcí, doporučuji použít metodu persist JPA.
Aktualizace oddělenou entitu
Při zavření aktuální vytrvalost souvislosti nebo explicitně odstranit entita od ní tím, že volá jasné, nebo odpojit metody EntityManager rozhraní, entity odpoutá. To znamená, že již není uložen v mezipaměti 1. úrovně a že hibernace nebude replikovat žádnou z aplikovaných změn v databázi.
můžete použít aktualizaci hibernace nebo metodu sloučení JPA k přidružení oddělené entity k kontextu persistence. Poté, co to uděláte, Hibernate aktualizuje databázi na základě hodnot atributů entity.
účinek metody aktualizace a sloučení se zdá být stejný, ale jak uvidíte v následujících částech, existuje důležitý rozdíl.
metoda sloučení JPA
metoda sloučení JPA zkopíruje stav oddělené entity do spravované instance stejné entity. Hibernace proto provede příkaz SQL SELECT a načte spravovanou entitu z databáze. Pokud kontext persistence již obsahoval spravovanou instanci entity, Hibernate místo toho použije existující instanci. Poté zkopíruje všechny hodnoty atributů do spravované entity a vrátí je volajícímu.
Author managedAuthor = em.merge(a);
po aktivaci protokolování příkazů SQL se ve výstupu protokolu zobrazí provedené příkazy SELECT a UPDATE.
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=?
když hibernace pro příště propláchne kontext persistence, jeho špinavý kontrolní mechanismus zkontroluje všechny spravované entity. Pokud zjistí, že operace sloučení změnila jakoukoli hodnotu atributu entity, spustí požadovaný příkaz SQL UPDATE.
existuje jeden důležitý detail, který potřebujete vědět, když používáte metodu sloučení JPA. Hibernace zkopíruje hodnoty atributů oddělené entity do spravované entity. Tím se přepíše všechny změny, které jste provedli na této entitě v rámci aktuální relace.
metoda aktualizace hibernace
metoda aktualizace hibernace nespustí příkaz SQL SELECT. To jen připojí entitu k současnému kontextu persistence. Na rozdíl od metody sloučení JPA nemůžete voláním metody aktualizace ztratit žádné změny. Pokud kontext persistence již obsahuje spravovanou instanci entity, kterou chcete aktualizovat, vyvolá výjimku.
em.unwrap(Session.class).update(a);
když hibernace provede další flush, neprovádí žádné špinavé kontroly. To není možné, protože Hibernate nečetl nejnovější verzi entity z databáze. Právě provádí příkaz SQL UPDATE Pro znovu připojenou entitu.
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=?
chybějící špinavá kontrola způsobí zbytečné prohlášení o aktualizaci SQL, pokud entita a odpovídající záznam databáze obsahují stejné hodnoty. To může být problém, pokud váš DBA zaregistroval spoušť aktualizace databázové tabulky. V těchto situacích můžete entitu komentovat pomocí @SelectBeforeUpdate.
@Entity@SelectBeforeUpdatepublic class Author { ... }
, Který říká Hibernace vyberte subjekt a provádět špinavé zkontrolovat před tím, než vytváří SQL příkazu UPDATE. Jak můžete vidět na výstupu protokolu, chování metody aktualizace je nyní podobné metodě sloučení JPA.
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=?
ale existuje významný rozdíl mezi 2 metodami. Když zavoláte metodu aktualizace, režim hibernace vybere pouze entitu, kterou jste zadali jako parametr metody. Ale když zavoláte metodu sloučení JPA, Hibernate také vybere všechna přidružení s CascadeType.SLOUČIT. Měli byste proto upřednostňovat metodu sloučení JPA, pokud znovu připojíte obrovský graf entit.
který z nich si vybrat?
na tyto otázky neexistuje obecná odpověď. Jak jste viděli, obě metody mají své výhody a nevýhody. Musíte se rozhodnout pro konkrétní případ použití, pokud hibernace potřebuje vybrat entitu před spuštěním příkazu SQL UPDATE. A pokud tomu tak je, musíte také zvážit hloubku grafu entity a důsledky výkonu poskytovaného chování načítání.
aktualizace spravované entity
JPA a hibernace usnadňují aktualizaci spravované entity. Pokud vaše bytost je v cyklu státu podařilo, např. protože jste vzali to s JPQL dotaz, nebo najít metody EntityManager, stačí změnit hodnoty vašich atributů.
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();
Když se Spánku rozhodne flush přetrvávání kontextu, znečištěný kontrola mechanismu bude detekovat změnu a provést požadované SQL příkazu UPDATE.
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=?
Nemusíte a po aktualizaci entity byste neměli volat metodu uložení hibernace. To spouští další událost SaveOrUpdate bez poskytnutí jakýchkoli výhod. Když se hibernace rozhodne propláchnout kontext perzistence, provede špinavou kontrolu, aby zjistil všechny změny, než provede požadované příkazy aktualizace SQL.