Wat is het verschil tussen persist, save, merge en update? Welke moet je gebruiken?

JPA en Hibernate bieden verschillende methoden om nieuwe entiteiten aan te houden en bestaande entiteiten bij te werken. U kunt kiezen tussen JPA ’s persist en merge en Hibernate’ s opslaan en bijwerken methoden.

het lijkt erop dat er 2 paren van 2 methoden zijn die hetzelfde doen. U kunt de methoden persist and save gebruiken om een nieuwe entiteit op te slaan en de methoden samenvoegen en bijwerken om de wijzigingen van een losstaande entiteit in de database op te slaan. Daarom vragen veel ontwikkelaars zich af welke van deze methoden ze moeten gebruiken. Laten we eens een kijkje op de details en kleine verschillen van deze methoden.

speciale dank aan Steve Ebersole (Lead Developer – Hibernate ORM) die zijn feedback en geweldige inzichten heeft gegeven over enkele verborgen implementatiedetails van Hibernate!

Entity State transities

voordat we ingaan op de details van deze 4 methoden, moet ik u een snelle inleiding geven tot de status van de entiteit van de JPA.

als een entiteit aan de huidige persistentiecontext is gekoppeld, wordt de levenscyclusstatus beheerd. Dat betekent dat het is toegewezen aan een database record. Uw persistence provider genereert de vereiste SQL INSERT en UPDATE statements om alle wijzigingen door te geven. Een beheerde entiteit wordt ook opgeslagen in de cache van het 1e niveau.

wanneer u een nieuwe entiteit maakt, is deze in de transiënte toestand. Het blijft in deze staat totdat je het koppelt aan de huidige persistentie context. Ik zal je laten zien hoe je dat kunt doen met JPA ’s persist en Hibernate’ s save methode, in de volgende sectie. Zolang een entiteit zich in de transiënte toestand bevindt, wordt deze niet toegewezen aan een databaserecord en wordt deze niet beheerd door een persistentiecontext.

entiteiten in de vrijstaande levenscyclus worden niet langer beheerd door de persistence context. Dat kan het geval zijn omdat je de persistence context hebt gesloten of je hebt de entiteit expliciet losgemaakt van de huidige context. Ik zal in meer details over hoe je deze entiteiten opnieuw kunt koppelen met JPA ’s merge en Hibernate’ s update methoden in een later deel van dit bericht.

en de laatste levenscyclusstatus wordt verwijderd. Deze entiteiten waren eerder in de staat beheerd, voordat u ze gepland voor verwijdering. Het verwijderen van entiteiten is buiten het bereik van deze post, dus Ik zal niet te veel details over te krijgen. U kunt een entiteit plannen voor verwijdering door het aanroepen van de methode verwijderen op de EntityManager interface.

een nieuwe entiteit aanhouden met persist of save

wanneer u een nieuw entiteitsobject maakt, bevindt het zich in de tijdelijke levenscyclus. Het geeft geen database-record in kaart.

Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");

u moet de entiteit aan een persistence context koppelen zodat deze wordt beheerd en in de database wordt opgenomen. U kunt JPA ’s persist of Hibernate’ s save methode gebruiken om dat te doen. Beide methoden lijken hetzelfde te doen, maar er zijn een paar verschillen.

specificatie vs. Propriëtaire API

het meest voor de hand liggende verschil is dat de JPA-specificatie de persist-methode definieert. U kunt het gebruiken met alle JPA-implementaties. De save methode, aan de andere kant, is Hibernate-specifiek. Het is derhalve niet beschikbaar in andere PPV-implementaties.

maar dat is alleen relevant als je Hibernate wilt kunnen vervangen door een andere JPA-implementatie, zoals Eclipse Link of OpenJPA.

Return Types And Execution Of SQL Statements

een ander duidelijk verschil tussen deze 2 methoden is hun return type. JPA ’s persist methode geeft void terug en Hibernate’ s save methode geeft de primaire sleutel van de entiteit terug.

dat lijkt misschien een enorm verschil, vooral als je een kijkje neemt op Hibernate ‘ s Javadoc en de JPA specificatie:

  • de Javadoc van Hibernate save methode stelt dat het genereert de primaire sleutel waarde eerste:

    de gegeven tijdelijke instantie aanhouden, eerst een gegenereerde identifier toewijzen.
    Javadoc-Sessie.opslaan (entiteit)

  • u vindt hier geen informatie over in de JPA specificatie. Het bepaalt niet wanneer de primaire sleutelwaarde moet worden toegewezen. Zo, de persistence provider kan dat doen op elk moment tussen de oproep van de persist methode en de flush van de persistence context.

in de meeste gevallen maakt het geen verschil als je de save of persist methode aanroept. Hibernate gebruikt de naam van de entiteitklasse en de primaire sleutelwaarde om de entiteit op te slaan in de cache van het eerste niveau. Het heeft daarom een primaire sleutelwaarde nodig wanneer het de persist-methode uitvoert.

in bijna alle situaties genereert Hibernate onmiddellijk de primaire sleutelwaarde en activeert zo nodig een SQL-statement wanneer u de persist or save-methode aanroept.

maar dat is niet het geval als u de IDENTITEITSSTRATEGIE gebruikt en een entiteit probeert voort te zetten zonder een actieve transactie of met FlushMode.HANDLEIDING. Als u de persist-methode in een van deze situaties aanroept, vertraagt Hibernate de uitvoering van het sql-INSERT-statement en creëert u een tijdelijke primaire sleutelwaarde. Maar als u de save-methode aanroept, voert Hibernate onmiddellijk het sql-INSERT-statement uit en haalt de primaire sleutelwaarde uit de database op.

u kunt het dan ophalen als de retourwaarde van de opslagmethode.

Author a = new Author();a.setFirstName("Thorben");a.setLastName("Janssen");Long id = (Long) em.unwrap(Session.class).save(a);

of u kunt de getter-methode van het primaire sleutelkenmerk van uw beheerde entiteit aanroepen als u de persist-methode van JPA gebruikt.

Author a = new Author();a.setFirstName("Torben");a.setLastName("Janssen");em.persist(a);Long id = a.getId();

Hibernate voert dezelfde SQL-statements uit wanneer u de persist of de save-methode aanroept. Welke en wanneer dat gebeurt, hangt af van uw primaire sleutel generatiestrategie:

niet gegenereerd

als u de primaire sleutelwaarde programmatisch instelt, bijvoorbeeld op een natuurlijke identifier, voert Hibernate alleen een SQL INSERT statement uit wanneer het de persistence context spoelt.

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 (?, ?, ?, ?)
YouTube-video

gegenereerd met IDENTITY strategy

Als u de IDENTITY strategy gebruikt om de primaire sleutelwaarde te genereren, moet Hibernate het insert statement uitvoeren wanneer u de save or persist method aanroept om de primaire sleutelwaarde uit de database op te halen.

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
YouTube-video

gegenereerd met SEQUENCE strategy

en als u de SEQUENCE gebruikt, voert Hibernate een SQL SELECT statement uit om de volgende waarde uit de database-sequence op te halen. Hibernate vertraagt dan het insert statement totdat het de persistence context spoelt. In dit voorbeeld gebeurt de flush wanneer de transactie wordt vastgelegd.

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 (?, ?, ?, ?)

gegenereerd met TABELSTRATEGIE

u zou de TABELSTRATEGIE niet moeten gebruiken omdat het rijniveau-vergrendelingen op de primaire sleuteltabel vereist en niet goed schaalt. Als je deze strategie toch gebruikt, voert Hibernate een SQL SELECT statement uit om de volgende primaire sleutelwaarde uit de database op te halen en schrijft de nieuwe waarde naar de database tabel. Het vertraagt de uitvoering van het SQL INSERT statement voor de nieuwe entiteit totdat het de persistence context spoelt.

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 (?, ?, ?, ?)

welke moet Ik kiezen?

je zou kunnen verwachten dat de save en persist methode zich anders gedragen omdat er een paar verschillen zijn tussen de JPA specificatie en de Javadoc van de eigen Hibernate methoden.

maar bijna al deze verschillen verdwijnen als je naar de interne implementatie kijkt. De enige die overblijven zijn 2 hoekgevallen waarin Hibernate het ophalen van de primaire sleutel, het retourtype van de methode en de ondersteuning door andere JPA-implementaties kan vertragen.

voor de meeste toepassingen maakt het geen verschil als u de gegenereerde primaire sleutelwaarde krijgt als het return type van de Save methode van Hibernate of van de getter methode van uw primaire sleutel attribuut. Zolang je geen extended persistence context gebruikt en alle database operaties uitvoert met een actieve transactie, adviseer ik het gebruik van JPA ‘ s persist methode.

een losstaande entiteit bijwerken

wanneer u de huidige persistentiecontext sluit of expliciet een entiteit eruit verwijdert door de clear-of loskoppelingsmethoden aan te roepen op de EntityManager-interface, wordt de entiteit losgemaakt. Dat betekent dat het niet langer wordt opgeslagen in het 1e niveau cache en dat Hibernate geen van de toegepaste wijzigingen in de database repliceren.

u kunt de update van Hibernate of de merge-methode van JPA gebruiken om een losstaande entiteit te koppelen aan een persistentiecontext. Nadat u dat hebt gedaan, Hibernate zal de database bij te werken op basis van de entiteit attribuut waarden.

het effect van de Bijwerken en samenvoegen methode lijkt hetzelfde te zijn, maar zoals u in de volgende paragrafen zult zien, is er een belangrijk verschil.

JPA ’s merge method

JPA’ s merge method kopieert de status van een losstaande entiteit naar een beheerde instantie van dezelfde entiteit. Hibernate voert daarom een SQL SELECT-statement uit om een beheerde entiteit uit de database op te halen. Als de persistence context al een beheerde instantie van de entiteit bevat, gebruikt Hibernate in plaats daarvan de bestaande. Het kopieert vervolgens alle attribuutwaarden naar de beheerde entiteit en geeft deze terug aan de beller.

Author managedAuthor = em.merge(a);

na het activeren van de logboekregistratie van SQL-statements, kunt u de uitgevoerde Select-en UPDATE-statements zien in de loguitvoer.

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=?

wanneer Hibernate de persistentiecontext voor de volgende keer spoelt, controleert het vuile controlemechanisme alle beheerde entiteiten. Als het detecteert dat de samenvoeg-bewerking een entiteit-attribuutwaarde heeft gewijzigd, wordt het vereiste SQL-UPDATE-statement geactiveerd.

er is één belangrijk detail dat u moet weten wanneer u JPA ‘ s merge methode gebruikt. Hibernate kopieert de attribuutwaarden van de losgemaakte entiteit naar de beheerde entiteit. Dit overschrijft alle wijzigingen die u binnen de huidige sessie op deze entiteit hebt uitgevoerd.

updatemethode voor Hibernate

updatemethode voor Hibernate leidt niet tot een SQL SELECT-statement. Het koppelt de entiteit aan de huidige persistentie context. In tegenstelling tot JPA ‘ s merge methode, kun je geen wijzigingen verliezen door de update methode aan te roepen. Als de persistence context al een beheerde instantie bevat van de entiteit die u wilt bijwerken, gooit het een uitzondering.

em.unwrap(Session.class).update(a);

wanneer Hibernate de volgende flush uitvoert, voert het geen vuile controles uit. Dat is niet mogelijk omdat Hibernate niet de nieuwste versie van de entiteit uit de database heeft gelezen. Het voert gewoon een SQL UPDATE statement uit voor de opnieuw aangekoppelde entiteit.

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=?

de ontbrekende ‘dirty check’ veroorzaakt een onnodig SQL-UPDATE-statement wanneer de entiteit en de bijbehorende databaserecord dezelfde waarden bevatten. Dit kan een probleem zijn als uw DBA een update trigger registreerde voor de database tabel. In deze situaties kunt u uw entiteit annoteren met @SelectBeforeUpdate.

@Entity@SelectBeforeUpdatepublic class Author { ... }

die Hibernate vertelt om de entiteit te selecteren en een vuile controle uit te voeren voordat het het SQL UPDATE statement genereert. Zoals je kunt zien in de log output, het gedrag van de update methode is nu vergelijkbaar met JPA ‘ s merge methode.

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=?

maar er is een significant verschil tussen de twee methoden. Wanneer u de updatemethode aanroept, selecteert Hibernate alleen de entiteit die u als methodeparameter hebt opgegeven. Maar als je JPA ‘ s merge methode aanroept, selecteert Hibernate ook alle associaties met CascadeType.SAMENVOEGEN. Je zou daarom de voorkeur moeten geven aan JPA ‘ s merge methode als je een enorme grafiek van entiteiten opnieuw koppelt.

welke moet Ik kiezen?

er is geen algemeen antwoord op deze vragen. Zoals u hebt gezien, hebben beide methoden hun voor-en nadelen. U moet voor uw specifieke use case beslissen of Hibernate de entiteit moet selecteren voordat het de SQL UPDATE statement activeert. En als dat het geval is, moet u ook rekening houden met de diepte van uw entiteit grafiek en de prestaties implicaties van het gegeven ophalen gedrag.

bijwerken van een beheerde entiteit

JPA en Hibernate maken het zeer eenvoudig om een beheerde entiteit bij te werken. Als uw entiteit in de levenscyclusstatus wordt beheerd, bijvoorbeeld omdat u het hebt opgehaald met een jpql-query of de zoekmethode van de EntityManager, hoeft u alleen maar de waarden van uw entity-attributen te wijzigen.

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();

wanneer Hibernate besluit om de persistence context te spoelen, zal het vuile controle mechanisme de verandering detecteren en het vereiste SQL UPDATE statement uitvoeren.

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=?

u hoeft dit niet te doen en u moet de save-methode van Hibernate niet aanroepen nadat u een entiteit hebt bijgewerkt. Dat leidt tot een extra SaveOrUpdate evenement zonder enige voordelen. Wanneer Hibernate besluit om de persistentie context te spoelen, zal het de vuile controle toch uitvoeren om alle wijzigingen te detecteren voordat het de vereiste SQL UPDATE statements uitvoert.

You might also like

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.