Hibernate: save, persist, update, merge, saveOrUpdate

Introduction

In dit artikel bespreken we de verschillen tussen verschillende methoden van de sessie-interface: save, persist, update, merge, saveOrUpdate.

dit is geen introductie tot Hibernate en u zou al de basisprincipes van configuratie, object-relationele toewijzing en het werken met entiteiten moeten kennen. Voor een inleidende artikel om te overwinteren, bezoek onze tutorial op overwinteren 4 met de lente.

verder lezen:

verwijderen van objecten met Hibernate

korte handleiding voor het verwijderen van een entiteit in Hibernate.
Lees meer →

opgeslagen Procedures met Hibernate

dit artikel bespreekt kort hoe u opslagprocedures vanuit Hibernate kunt aanroepen.
Lees meer →

een overzicht van Identifiers in Hibernate / JPA

leer hoe entiteitidentifiers met Hibernate kunnen worden toegewezen.
Lees meer →

Session as a Persistence Context Implementation

de sessie interface heeft verschillende methoden die uiteindelijk resulteren in het opslaan van gegevens in de database: persist, save, update, merge, saveOrUpdate. Om het verschil tussen deze methoden te begrijpen, moeten we eerst het doel van de sessie als een persistentiecontext bespreken en het verschil tussen de toestanden van entiteiten in relatie tot de sessie.

we moeten ook de geschiedenis van de ontwikkeling van Hibernate begrijpen die leidde tot enkele gedeeltelijk gedupliceerde API-methoden.

2.1. Beheersentiteit Instances

afgezien van object-relationele mapping zelf, is een van de problemen die Hibernate moest oplossen het probleem van het beheren van entiteiten tijdens runtime. De notie van “persistentie context” is Hibernate ‘ s oplossing voor dit probleem. Persistentie context kan worden gezien als een container of een eerste niveau cache voor alle objecten die u geladen of opgeslagen in een database tijdens een sessie.

de sessie is een logische transactie, welke grenzen worden gedefinieerd door de zakelijke logica van uw toepassing. Als je met de database werkt door middel van een persistence context, en al je entity instanties zijn gekoppeld aan deze context, moet je altijd een enkele instantie van entiteit hebben voor elke database record dat je hebt interactie tijdens de sessie met.

in de winterslaap wordt de persistentiecontext weergegeven door org.slaapstand.Sessie-instantie. Voor JPA is het de javax.persistentie.EntityManager. Wanneer we Hibernate gebruiken als een JPA-provider en werken via EntityManager-interface, wikkelt de implementatie van deze interface in principe het onderliggende Sessieobject. Echter, Hibernate sessie biedt een rijkere interface met meer mogelijkheden, dus soms is het handig om te werken met sessie direct.

2.2. Staten van entiteiten-instanties

elke entiteit-instantie in uw toepassing verschijnt in een van de drie belangrijkste staten met betrekking tot de sessie-persistentie-context:

  • transiënte-deze instantie is niet, en was nooit, gekoppeld aan een sessie; deze instantie heeft geen overeenkomstige rijen in de database; het is meestal gewoon een nieuw object dat u hebt gemaakt om op te slaan in de database;
  • persistent-deze instantie is geassocieerd met een uniek Sessieobject; na het doorspoelen van de sessie naar de database, heeft deze entiteit gegarandeerd een overeenkomstige consistente record in de database;
  • losgemaakt — deze instantie was ooit aan een sessie gekoppeld (in een permanente toestand), maar nu niet meer; een instantie komt in deze toestand als u het uit de context verwijdert, de sessie verwijdert of sluit, of de instantie door serialisatie/deserialisatie proces laat gaan.

hier is een vereenvoudigd toestandsdiagram met opmerkingen over Sessiemethoden die de toestandsovergangen mogelijk maken.

2016-07-11_13-38-11

wanneer de instantie van de entiteit in de permanente toestand is, zullen alle wijzigingen die u aanbrengt in de toegewezen velden van deze instantie worden toegepast op de overeenkomstige databaserecords en-Velden bij het doorspoelen van de sessie. De persistent instantie kan worden gezien als “online”, terwijl de losstaande instantie is gegaan” offline ” en wordt niet gecontroleerd op Wijzigingen.

dit betekent dat wanneer u de velden van een permanent object wijzigt, u geen opslaan, bijwerken of een van deze methoden hoeft aan te roepen om deze wijzigingen in de database te krijgen: alles wat u nodig hebt is de transactie te committen, of de sessie te flushen of te sluiten, wanneer u ermee klaar bent.

2.3. Conformiteit met JPA-specificatie

Hibernate was de meest succesvolle Java ORM-implementatie. Geen wonder dat de specificatie voor Java persistence API (JPA) sterk werd beïnvloed door de Hibernate API. Helaas waren er ook veel verschillen: sommige groot, sommige subtieler.

om op te treden als een implementatie van de PPA-standaard, moesten Hibernate API ‘ s worden herzien. Verschillende methoden werden toegevoegd aan de sessie-interface om de EntityManager-interface overeen te komen. Deze methoden dienen hetzelfde doel als de “oorspronkelijke” methoden, maar voldoen aan de specificatie en hebben dus enkele verschillen.

verschillen tussen de bewerkingen

het is belangrijk om vanaf het begin te begrijpen dat alle methoden (persist, save, update, merge, saveOrUpdate) niet onmiddellijk resulteren in de overeenkomstige SQL UPDATE of INSERT statements. De daadwerkelijke opslag van gegevens in de database vindt plaats bij het committen van de transactie of het doorspoelen van de sessie.

de genoemde methoden beheren in principe de staat van entiteiten door ze over te schakelen tussen verschillende staten gedurende de levenscyclus.

als een voorbeeld entiteit, zullen we een eenvoudige annotatie-toegewezen entiteit persoon gebruiken:

@Entitypublic class Person { @Id @GeneratedValue private Long id; private String name; // ... getters and setters}

3.1. Persist

de persist-methode is bedoeld om een nieuwe entiteit-instantie toe te voegen aan de Persistance-context, dat wil zeggen om een instantie van transiënte naar persistente toestand over te zetten.

we noemen het meestal als we een record aan de database willen toevoegen (persist an entity instance):

Person person = new Person();person.setName("John");session.persist(person);

Wat gebeurt er nadat de persist-methode wordt genoemd? Het persoonsobject is overgestapt van voorbijgaande naar blijvende toestand. Het object bevindt zich nu in de persistence context, maar nog niet opgeslagen in de database. Het genereren van INSERT statements zal alleen plaatsvinden bij het uitvoeren van de transactie, het doorspoelen of het sluiten van de sessie.

merk op dat de persist methode een void return type heeft. Het werkt op het doorgegeven object “op zijn plaats”, het veranderen van de toestand. De persoonsvariabele verwijst naar het daadwerkelijk persisted object.

deze methode is een latere toevoeging aan de Sessieinterface. Het belangrijkste onderscheidende kenmerk van deze methode is dat het voldoet aan de JSR-220 specificatie (EJB persistentie). De semantiek van deze methode is strikt gedefinieerd in de specificatie, die in principe stelt, dat:

  • een transiënte instantie wordt persistent (en de operatie cascades naar al haar relaties met cascade=PERSIST of cascade=ALL),
  • als een instantie al persistent is, dan heeft deze aanroep geen effect voor deze specifieke instantie (maar het cascades nog steeds naar zijn relaties met cascade=PERSIST of cascade=ALL),
  • als een instantie wordt losgemaakt, moet u een uitzondering verwachten, hetzij bij het aanroepen van deze methode, hetzij bij het committen of doorspoelen van de sessie.

merk op dat er hier niets is dat betrekking heeft op de identifier van een instantie. De spec staat niet dat de id zal worden gegenereerd meteen, ongeacht de ID generatie strategie. De specificatie voor de persist methode staat de implementatie toe om statements uit te geven voor het genereren van id op commit of flush, en het id is niet gegarandeerd niet-null te zijn na het aanroepen van deze methode, dus je moet er niet op vertrouwen.

u kunt deze methode aanroepen op een reeds aanhoudende instantie, en er gebeurt niets. Maar als je probeert een losstaande instantie aan te houden, is de implementatie gebonden aan een uitzondering te gooien. In het volgende voorbeeld zetten we de entiteit voort, zetten het uit de context zodat het onthecht raakt, en proberen dan opnieuw te volharden. De tweede oproep voor de sessie.persist() veroorzaakt een uitzondering, dus de volgende code zal niet werken:

Person person = new Person();person.setName("John");session.persist(person);session.evict(person);session.persist(person); // PersistenceException!

3.2. Save

de save methode is een “originele” Hibernate methode die niet voldoet aan de JPA specificatie.

het doel is in principe hetzelfde als persist, maar het heeft verschillende uitvoeringsdetails. De documentatie voor deze methode stelt strikt dat het de instantie blijft, “eerst het toewijzen van een gegenereerde identifier”. De methode is gegarandeerd om de Serialiseerbare waarde van deze identifier terug te geven.

Person person = new Person();person.setName("John");Long id = (Long) session.save(person);

het effect van het opslaan van een reeds bestaande instantie is hetzelfde als met persist. Verschil komt wanneer je probeert om een losstaande instantie op te slaan:

Person person = new Person();person.setName("John");Long id1 = (Long) session.save(person);session.evict(person);Long id2 = (Long) session.save(person);

de id2 variabele zal verschillen van id1. De aanroep van save op een losstaande instantie maakt een nieuwe persistent instantie en wijst het een nieuwe identifier toe, wat resulteert in een dubbele record in een database bij het committen of doorspoelen.

3.3. Merge

de belangrijkste bedoeling van de merge methode is om een persistente entiteit instantie bij te werken met nieuwe veldwaarden van een losstaande entiteit instantie.

bijvoorbeeld, stel dat je een RESTful interface hebt met een methode voor het ophalen van een JSON-serialized object door zijn id aan de beller en een methode die een bijgewerkte versie van dit object ontvangt van de beller. Een entiteit die door een dergelijke serialisatie/deserialisatie is gegaan, zal in een ontkoppelde staat verschijnen.

na het deserialiseren van deze entiteit instantie, moet u een persistent entiteit instantie uit een persistence context halen en de velden bijwerken met nieuwe waarden van deze losstaande instantie. Dus de merge methode doet precies dat:

  • vindt een entiteit instantie door id genomen uit het doorgegeven object (ofwel een bestaande entiteit instantie uit de persistence context wordt opgehaald, of een nieuwe instantie geladen uit de database);
  • kopieert velden van het doorgegeven object naar deze instantie;
  • geeft nieuw bijgewerkt exemplaar.

In het volgende voorbeeld verwijderen we de opgeslagen entiteit uit de context, veranderen we het naamveld en voegen de losgemaakte entiteit samen.

Person person = new Person(); person.setName("John"); session.save(person);session.evict(person);person.setName("Mary");Person mergedPerson = (Person) session.merge(person);

merk op dat de merge methode een object retourneert — het is het mergedPerson object dat in de persistence context is geladen en is bijgewerkt, niet het persoon object dat u als argument hebt opgegeven. Dat zijn twee verschillende objecten, en de persoon object meestal moet worden weggegooid (hoe dan ook, reken er niet op dat het wordt gekoppeld aan persistentie context).

Als met het aanhouden methode, de merge methode is opgegeven door JSR-220 bepaalde semantiek dat u kunt vertrouwen op:

  • als de entiteit is losgekomen, het is gekopieerd op een bestaande blijvende entiteit;
  • als de entiteit is van voorbijgaande aard, het is gekopieerd op een nieuwe permanente entiteit;
  • deze bewerking cascades voor alle betrekkingen met de cascade=SAMENVOEGEN of cascade=ALLE mapping;
  • als de entiteit is persistent, dan is dit een aanroep van de methode heeft geen effect op het (maar de trapsgewijze plaatsvindt).

3.4. Update

net als bij persist en save, is de update-methode een” originele ” Hibernate-methode die al lang aanwezig was voordat de merge-methode werd toegevoegd. De semantiek verschilt in verschillende belangrijke punten:

  • het werkt op doorgegeven object (zijn return type is void); de update methode zet het doorgegeven object over van ontkoppeld naar persistent status;
  • deze methode gooit een uitzondering als je het een transiënte entiteit passeert.

in het volgende voorbeeld slaan we het object op, verwijderen het uit de context, veranderen de naam en bellen we update. Merk op dat we het resultaat van de update operatie niet in een aparte variabele plaatsen, omdat de update plaatsvindt op het persoon object zelf. In principe koppelen we de bestaande entiteit instantie opnieuw aan de persistence context — iets wat de JPA specificatie ons niet toestaat om te doen.

Person person = new Person();person.setName("John");session.save(person);session.evict(person);person.setName("Mary");session.update(person);

proberen om update aan te roepen op een transiënte instantie zal resulteren in een uitzondering. Het volgende zal niet werken:

Person person = new Person();person.setName("John");session.update(person); // PersistenceException!

3.5. SaveOrUpdate

deze methode verschijnt alleen in de Hibernate API en heeft geen gestandaardiseerde tegenhanger. Vergelijkbaar met update, het kan ook worden gebruikt voor het opnieuw koppelen van instanties.

in feite is de interne DefaultUpdateEventListener klasse die de update methode verwerkt een subklasse van DefaultSaveOrUpdateListener, die slechts enkele functionaliteit overstijgt. Het belangrijkste verschil van saveorupdate methode is dat het geen uitzondering gooien wanneer toegepast op een voorbijgaande instantie; in plaats daarvan, het maakt deze voorbijgaande instantie persistent. De volgende code zal een nieuw aangemaakte instantie van persoon blijven bestaan:

Person person = new Person();person.setName("John");session.saveOrUpdate(person);

u kunt deze methode beschouwen als een universeel hulpmiddel om een object blijvend te maken, ongeacht de toestand ervan of het van voorbijgaande aard is of los staat.

Wat moet u gebruiken?

als u geen speciale vereisten heeft, moet u als vuistregel vasthouden aan de persist en merge methoden, omdat ze gestandaardiseerd zijn en gegarandeerd voldoen aan de JPA specificatie.

ze zijn ook portable in het geval u besluit om over te schakelen naar een andere persistence provider, maar ze kunnen soms niet zo nuttig lijken als de “originele” Hibernate methoden, opslaan, bijwerken en saveOrUpdate.

conclusie

we hebben het doel van verschillende Hibernate Session methoden besproken in relatie tot het beheren van persistente entiteiten in runtime. We hebben geleerd hoe deze methoden entiteiten transisteren door hun levenscyclus en waarom sommige van deze methoden hebben gedupliceerde functionaliteit.



+