Slaapstand: opslaan, voortzetten, bijwerken, samenvoegen, saveOrUpdate

1. Inleiding

In dit artikel bespreken we de verschillen tussen verschillende methoden van de Sessie koppel: sparen, volharden, bijwerken, samenvoegen, saveOrUpdate.

Dit is geen inleiding tot Hibernate en u zou al de basisprincipes van configuratie, object-relationele toewijzing en het werken met entiteitsinstanties moeten kennen. Bezoek onze tutorial over Hibernate 4 met Spring voor een inleidend artikel over Hibernate.

2. Sessie als implementatie van een persistentiecontext

De Sessie interface heeft verschillende methoden die uiteindelijk resulteren in het opslaan van gegevens in de database: volharden, sparen, bijwerken, samenvoegen, saveOrUpdate. Om het verschil tussen deze methoden te begrijpen, moeten we eerst het doel van de Sessie als een persistentiecontext en het verschil tussen de toestanden van entiteitinstanties in relatie tot de Sessie.

We moeten ook de geschiedenis begrijpen van de ontwikkeling van Hibernate die heeft geleid tot een aantal gedeeltelijk gedupliceerde API-methoden.

2.1. Entiteitsinstanties beheren

Afgezien van object-relationele mapping zelf, is een van de problemen die Hibernate moest oplossen, het probleem van het beheren van entiteiten tijdens runtime. Het begrip "persistentiecontext" is de oplossing van Hibernate voor dit probleem. Persistentiecontext kan worden gezien als een container of een cache op het eerste niveau voor alle objecten die u tijdens een sessie in een database hebt geladen of opgeslagen.

De sessie is een logische transactie, waarvan de grenzen worden bepaald door de bedrijfslogica van uw app. Wanneer u met de database werkt via een persistentiecontext, en al uw entiteitsinstanties zijn aan deze context gekoppeld, moet u altijd één exemplaar van de entiteit hebben voor elk databaserecord waarmee u interactie hebt gehad tijdens de sessie.

In Hibernate wordt de persistentiecontext weergegeven door org.hibernate.Session voorbeeld. Voor JPA is het de javax.persistence.EntityManager. Wanneer we Hibernate gebruiken als een JPA-provider en opereren via EntityManager interface, de implementatie van deze interface omhult in feite de onderliggende Sessie voorwerp. Slaapstand Sessie biedt een rijkere interface met meer mogelijkheden, dus soms is het handig om mee te werken Directe sessie.

2.2. Staten van instanties van entiteiten

Elke entiteitsinstantie in uw toepassing wordt weergegeven in een van de drie hoofdstatussen met betrekking tot het Sessie persistentie context:

  • voorbijgaand - deze instantie is niet gekoppeld aan een Sessie; dit exemplaar heeft geen overeenkomstige rijen in de database; het is meestal gewoon een nieuw object dat u heeft gemaakt om op te slaan in de database;
  • aanhoudend - deze instantie is gekoppeld aan een uniek Sessie voorwerp; bij het doorspoelen van de Sessie voor de database is deze entiteit gegarandeerd een overeenkomstig consistent record in de database;
  • vrijstaand - deze instantie was ooit gekoppeld aan een Sessie (in een aanhoudend state), maar nu is het niet; een instantie komt in deze toestand als u deze uit de context verwijdert, de sessie wist of sluit, of de instantie door een serialisatie- / deserialiseringsproces leidt.

Hier is een vereenvoudigd toestandsdiagram met opmerkingen over Sessie methoden die de toestandsovergangen mogelijk maken.

Wanneer de entiteitsinstantie zich in de aanhoudend state, zullen alle wijzigingen die u aanbrengt in de toegewezen velden van deze instantie worden toegepast op de corresponderende databaserecords en velden bij het leegmaken van de Sessie. De aanhoudend instantie kan worden gezien als "online", terwijl de vrijstaand instantie is "offline" gegaan en wordt niet gecontroleerd op wijzigingen.

Dit betekent dat wanneer u velden van een aanhoudend object, je hoeft niet te bellen sparen, bijwerken of een van die methoden om deze wijzigingen in de database te krijgen: alles wat je nodig hebt, is de transactie vastleggen, of de sessie leegmaken of sluiten, als je er klaar mee 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 te fungeren als een implementatie van de JPA-standaard, moesten de Hibernate-API's worden herzien. Er zijn verschillende methoden toegevoegd aan de sessie-interface om overeen te komen met de EntityManager-interface. Deze methoden dienen hetzelfde doel als de "originele" methoden, maar voldoen aan de specificatie en hebben dus enkele verschillen.

3. Verschillen tussen de operaties

Het is belangrijk om vanaf het begin te begrijpen dat alle methoden (volharden, sparen, bijwerken, samenvoegen, saveOrUpdate) resulteren niet onmiddellijk in de bijbehorende SQL BIJWERKEN of INVOEGEN verklaringen. Het daadwerkelijke opslaan van gegevens in de database vindt plaats bij het plegen van de transactie of het wissen van het Sessie.

De genoemde methoden beheren in feite de status van entiteitsinstanties door ze tijdens de levenscyclus tussen verschillende statussen over te zetten.

Als voorbeeldentiteit gebruiken we een eenvoudige entiteit die is toegewezen aan annotaties Persoon:

@Entity openbare klasse Persoon {@Id @GeneratedValue privé Lange id; private String naam; // ... getters en setters}

3.1. Volhouden

De volharden methode is bedoeld voor het toevoegen van een nieuwe entiteitsinstantie aan de persistentiecontext, d.w.z. het overzetten van een instantie van tijdelijk naar aanhoudend staat.

We noemen het meestal wanneer we een record aan de database willen toevoegen (een entiteitsinstantie behouden):

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.persist (persoon);

Wat gebeurt er na de volharden methode heet? De persoon object is overgegaan van voorbijgaand naar aanhoudend staat. Het object bevindt zich nu in de persistentiecontext, maar is nog niet opgeslagen in de database. De generatie van INVOEGEN verklaringen zullen alleen plaatsvinden bij het plegen van de transactie, het opschonen of het sluiten van de sessie.

Merk op dat de volharden methode heeft leegte retourtype. Het werkt op het doorgegeven object "op zijn plaats" en verandert zijn toestand. De persoon variabele verwijst naar het feitelijke persistente object.

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

  • een voorbijgaand instantie wordt aanhoudend (en de operatie stroomt naar al zijn relaties met cascade = PERSIST of cascade = ALL),
  • als er al een instantie is aanhoudend, dan heeft deze aanroep geen effect voor dit specifieke exemplaar (maar het stroomt nog steeds naar zijn relaties met cascade = PERSIST of cascade = ALLE),
  • als een instantie is vrijstaand, moet u een uitzondering verwachten, hetzij bij het aanroepen van deze methode, of bij het plegen of doorspoelen van de sessie.

Merk op dat er hier niets is dat betrekking heeft op de identifier van een instantie. In de specificatie staat niet dat de id meteen wordt gegenereerd, ongeacht de strategie voor het genereren van id's. De specificatie voor de volharden method staat de implementatie toe om instructies te geven voor het genereren van id bij commit of flush, en het is niet gegarandeerd dat de id niet-null is na het aanroepen van deze methode, dus je moet er niet op vertrouwen.

U kunt deze methode al aanroepen aanhoudend bijvoorbeeld, en er gebeurt niets. Maar als u probeert een vrijstaand de implementatie zal bijvoorbeeld een uitzondering genereren. In het volgende voorbeeld hebben we volharden de entiteit, uitzetten het uit de context zodat het wordt vrijstaand, en probeer het dan volharden opnieuw. De tweede oproep aan session.persist () veroorzaakt een uitzondering, dus de volgende code zal niet werken:

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.persist (persoon); session.evict (persoon); session.persist (persoon); // PersistenceException!

3.2. Sparen

De sparen methode is een "originele" Hibernate-methode die niet voldoet aan de JPA-specificatie.

Het doel is in wezen hetzelfde als volharden, maar het heeft verschillende implementatiedetails. De documentatie voor deze methode stelt strikt dat het de instantie blijft behouden, "eerst een gegenereerde identifier toewijzen". De methode retourneert gegarandeerd de Serialiseerbaar waarde van deze identifier.

Persoon persoon = nieuwe persoon (); person.setName ("John"); Long id = (Long) session.save (persoon);

Het effect van het opslaan van een reeds bestaande instantie is hetzelfde als bij volharden. Het verschil komt wanneer u een vrijstaand voorbeeld:

Persoon persoon = nieuwe persoon (); person.setName ("John"); Lange id1 = (Lange) session.save (persoon); session.evict (persoon); Lange id2 = (Lange) session.save (persoon);

De id2 variabele zal verschillen van id1. De oproep om te besparen op een vrijstaand instantie maakt een nieuw aanhoudend instantie en wijst er een nieuwe identifier aan toe, wat resulteert in een dubbel record in een database bij vastleggen of wissen.

3.3. Samenvoegen

De belangrijkste bedoeling van de samenvoegen methode is om een aanhoudend entiteitsinstantie met nieuwe veldwaarden van een vrijstaand entiteitsinstantie.

Stel dat u een RESTful-interface heeft met een methode voor het ophalen van een JSON-geserialiseerd object op ID naar de beller en een methode die een bijgewerkte versie van dit object van de beller ontvangt. Een entiteit die een dergelijke serialisatie / deserialisatie heeft doorgemaakt, wordt weergegeven in een vrijstaand staat.

Nadat u deze entiteitsinstantie heeft gedeserialiseerd, moet u een aanhoudend entiteitsinstantie vanuit een persistentiecontext en werk zijn velden bij met nieuwe waarden hiervan vrijstaand voorbeeld. Dus de samenvoegen methode doet precies dat:

  • vindt een entiteitsinstantie op ID genomen uit het doorgegeven object (ofwel wordt een bestaande entiteitsinstantie uit de persistentiecontext opgehaald, ofwel wordt een nieuw exemplaar geladen uit de database);
  • kopieert velden van het doorgegeven object naar deze instantie;
  • geeft een nieuw bijgewerkte instantie terug.

In het volgende voorbeeld hebben we uitzetten (ontkoppel) de opgeslagen entiteit van de context, verander het naam veld, en dan samenvoegen de vrijstaand entiteit.

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.save (persoon); session.evict (persoon); person.setName ("Mary"); Persoon mergedPerson = (Persoon) session.merge (persoon);

Merk op dat de samenvoegen methode retourneert een object - het is de mergedPerson object dat in persistentiecontext is geladen en is bijgewerkt, niet het persoon object dat je hebt doorgegeven als argument. Dat zijn twee verschillende objecten, en de persoon object moet meestal worden weggegooid (reken er in ieder geval niet op dat het aan persistentiecontext wordt gehecht).

Net als bij volharden methode, de samenvoegen methode is gespecificeerd door JSR-220 om bepaalde semantiek te hebben waarop u kunt vertrouwen:

  • als de entiteit is vrijstaand, wordt het gekopieerd naar een bestaand aanhoudend entiteit;
  • als de entiteit is voorbijgaand, wordt het gekopieerd naar een nieuw gemaakt aanhoudend entiteit;
  • deze operatie cascades voor alle relaties met cascade = SAMENVOEGEN of cascade = ALLE in kaart brengen;
  • als de entiteit is aanhoudend, dan heeft deze methodeaanroep er geen effect op (maar de cascadering vindt nog steeds plaats).

3.4. Bijwerken

Net als bij volharden en sparen, de bijwerken -methode is een "originele" Hibernate-methode die al lang vóór de samenvoegen methode is toegevoegd. De semantiek verschilt op verschillende belangrijke punten:

  • het werkt op het doorgegeven object (het retourtype is leegte); de bijwerken methode zet het doorgegeven object over van vrijstaand naar aanhoudend staat;
  • deze methode genereert een uitzondering als je het een voorbijgaand entiteit.

In het volgende voorbeeld hebben we sparen het object dan uitzetten (ontkoppel) het van de context en verander dan het naam en bel bijwerken. Merk op dat we het resultaat van de bijwerken bewerking in een afzonderlijke variabele, omdat de bijwerken vindt plaats op de persoon object zelf. In feite koppelen we de bestaande entiteitsinstantie opnieuw aan de persistentiecontext - iets wat de JPA-specificatie ons niet toestaat.

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.save (persoon); session.evict (persoon); person.setName ("Mary"); session.update (persoon);

Ik probeer te bellen bijwerken op een voorbijgaand instantie zal resulteren in een uitzondering. Het volgende werkt niet:

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.update (persoon); // PersistenceException!

3.5. SaveOrUpdate

Deze methode verschijnt alleen in de Hibernate-API en heeft geen gestandaardiseerde tegenhanger. Gelijkwaardig aan bijwerken, kan het ook worden gebruikt voor het opnieuw bevestigen van instanties.

Eigenlijk de interne DefaultUpdateEventListener klasse die de bijwerken methode is een subklasse van DefaultSaveOrUpdateListener, gewoon een aantal functionaliteit overschrijven. Het belangrijkste verschil van saveOrUpdate methode is dat het geen uitzondering genereert wanneer het wordt toegepast op een voorbijgaand voorbeeld; in plaats daarvan maakt het dit voorbijgaand voorbeeld aanhoudend. De volgende code zal een nieuw aangemaakt exemplaar van Persoon:

Persoon persoon = nieuwe persoon (); person.setName ("John"); session.saveOrUpdate (persoon);

U kunt deze methode zien als een universeel hulpmiddel om een ​​object te maken aanhoudend ongeacht de staat of het is voorbijgaand of vrijstaand.

4. Wat te gebruiken?

Als u geen speciale vereisten heeft, dient u zich als vuistregel aan de volharden en samenvoegen methoden, omdat ze gestandaardiseerd zijn en gegarandeerd voldoen aan de JPA-specificatie.

Ze zijn ook draagbaar voor het geval u besluit over te schakelen naar een andere persistentieprovider, maar ze kunnen soms niet zo nuttig lijken als de "originele" Hibernate-methoden, sparen, bijwerken en saveOrUpdate.

5. Conclusie

We hebben het doel van verschillende Hibernate Session-methoden besproken met betrekking tot het beheren van persistente entiteiten in runtime. We hebben geleerd hoe deze methoden entiteitsinstanties transisteren tijdens hun levenscycli en waarom sommige van deze methoden dubbele functionaliteit hebben.

De broncode voor het artikel is beschikbaar op GitHub.