Hibernate: save, persistate, update, merge, saveOrUpdate

introduktion

i denne artikel vil vi diskutere forskellene mellem flere metoder til Sessiongrænsefladen: save, persistate, update, merge, saveOrUpdate.

dette er ikke en introduktion til Hibernate, og du bør allerede kende det grundlæggende i konfiguration, objekt-relationel kortlægning og arbejde med enhedsinstanser. For en introduktionsartikel, der skal dvale, kan du besøge vores tutorial om Hibernate 4 med foråret.

yderligere læsning:

sletning af objekter med Hibernate

hurtig guide til sletning af en enhed i Hibernate.
Læs mere →

lagrede procedurer med Hibernate

denne artikel beskriver kort, hvordan man kalder store procedurer fra Hibernate.
Læs mere →

en oversigt over identifikatorer i Hibernate/JPA

Lær, hvordan du kortlægger enhedsidentifikatorer med Hibernate.
Læs mere →

Session som en Persistens kontekst implementering

Sessionsgrænsefladen har flere metoder, der til sidst resulterer i at gemme data i databasen: vedvar, Gem, Opdater, Flet, gemorupdate. For at forstå forskellen mellem disse metoder skal vi først diskutere formålet med sessionen som en vedholdenhedskontekst og forskellen mellem tilstandene for enhedsinstanser i forhold til sessionen.

vi bør også forstå historien om Hibernate udvikling, der førte til nogle delvist duplikerede API metoder.

2.1. Administrationsenhedsinstanser

bortset fra selve objekt-relationel kortlægning er et af de problemer, som Hibernate var beregnet til at løse, problemet med at styre enheder under runtime. Begrebet” vedholdenhedskontekst ” er hibernates løsning på dette problem. Persistenskontekst kan betragtes som en container eller en cache på første niveau for alle de objekter, du har indlæst eller gemt i en database under en session.

sessionen er en logisk transaktion, som grænser er defineret af din applikations forretningslogik. Når du arbejder med databasen gennem en persistenskontekst, og alle dine enhedsinstanser er knyttet til denne kontekst, skal du altid have en enkelt forekomst af enhed for hver databasepost, du har interageret under sessionen med.

i dvaletilstand er persistenskonteksten repræsenteret af org.dvale.Session forekomst. For JPA er det javaksen.vedholdenhed.EntityManager. Når vi bruger Hibernate som JPA-udbyder og opererer via EntityManager-interface, ombrydes implementeringen af denne grænseflade grundlæggende det underliggende Sessionsobjekt. Hibernate Session giver dog en rigere grænseflade med flere muligheder, så nogle gange er det nyttigt at arbejde direkte med Session.

2.2. Tilstander for Enhedsinstanser

enhver enhedsinstans i din ansøgning vises i en af de tre hovedtilstande i forhold til sessionens persistenskontekst:

  • transient – denne forekomst er ikke og blev aldrig knyttet til en Session; denne forekomst har ingen tilsvarende rækker i databasen; det er normalt bare et nyt objekt, du har oprettet for at gemme i databasen;
  • vedvarende — denne forekomst er forbundet med et unikt Sessionobjekt; efter skylning af sessionen til databasen garanteres denne enhed at have en tilsvarende konsistent post i databasen;
  • løsrevet — denne forekomst var engang knyttet til en Session (i en vedvarende tilstand), men nu er det ikke; en forekomst går ind i denne tilstand, hvis du udsætter den fra konteksten, rydder eller lukker sessionen eller sætter forekomsten gennem serialisering/deserialiseringsproces.

her er et forenklet tilstandsdiagram med kommentarer til Sessionsmetoder, der får tilstandsovergangene til at ske.

2016-07-11_13-38-11

når enhedsforekomsten er i vedvarende tilstand, vil alle ændringer, du foretager i de tilknyttede felter i denne forekomst, blive anvendt på de tilsvarende databaseposter og felter, når sessionen skylles. Den vedvarende forekomst kan betragtes som” online”, mens den løsrevne forekomst er gået” offline ” og ikke overvåges for ændringer.

dette betyder, at når du ændrer felter i et vedvarende objekt, behøver du ikke ringe til Gem, Opdater eller nogen af disse metoder for at få disse ændringer til databasen: alt hvad du behøver er at begå transaktionen eller skylle eller lukke sessionen, når du er færdig med det.

2.3. Overensstemmelse med JPA specifikation

Hibernate var den mest succesfulde Java ORM implementering. Ikke underligt, at specifikationen for Java persistence API (JPA) var stærkt påvirket af Hibernate API. Desværre var der også mange forskelle: nogle store, nogle mere subtile.

for at fungere som en implementering af JPA-standarden måtte Hibernate API ‘ er revideres. Flere metoder blev tilføjet til Session interface til at matche EntityManager interface. Disse metoder tjener det samme formål som de “originale” metoder, men er i overensstemmelse med specifikationen og har således nogle forskelle.

forskelle mellem operationerne

det er vigtigt at forstå fra starten, at alle metoderne (vedvarer, Gem, Opdater, Flet, gemopdatering) ikke umiddelbart resulterer i den tilsvarende opdatering eller indsæt udsagn. Den faktiske lagring af data til databasen sker ved at begå transaktionen eller skylle sessionen.

de nævnte metoder styrer grundlæggende tilstanden af enhedsinstanser ved at overføre dem mellem forskellige tilstande langs livscyklussen.

som et eksempel enhed, vil vi bruge en simpel annotation-kortlagt enhed Person:

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

3.1. Persistere

persistere-metoden er beregnet til at tilføje en ny enhedsinstans til persistenskonteksten, dvs.overføre en forekomst fra forbigående til vedvarende tilstand.

vi kalder det normalt, når vi vil tilføje en post til databasen (Fortsæt en enhedsinstans):

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

Hvad sker der efter vedvarende metode kaldes? Personobjektet er overgået fra forbigående til vedvarende tilstand. Objektet er i persistens sammenhæng nu, men endnu ikke gemt i databasen. Genereringen af INSERT-udsagn vil kun ske, når transaktionen påbegyndes, skyller eller lukker sessionen.

Bemærk, at vedvarende metode har ugyldig returtype. Den opererer på det passerede objekt “på plads” og ændrer sin tilstand. Personvariablen refererer til det faktiske vedvarende objekt.

denne metode er en senere tilføjelse til Sessiongrænsefladen. Det vigtigste differentierende træk ved denne metode er, at den er i overensstemmelse med JSR-220-specifikationen (EJB persistens). Semantikken i denne metode er strengt defineret i specifikationen, som grundlæggende siger, at:

  • en forbigående forekomst bliver vedvarende (og operationen kaskader til alle dens forbindelser med cascade=PERSISTATE eller cascade=ALL),
  • hvis en forekomst allerede er vedvarende, har dette opkald Ingen virkning for denne særlige forekomst (men det kaskader stadig til dets forhold til cascade=PERSISTATE eller cascade=ALL),
  • hvis en forekomst er løsrevet, skal du forvente en undtagelse, enten ved at kalde denne metode eller ved at begå eller skylle sessionen .

Bemærk, at der ikke er noget her, der vedrører identifikatoren for en forekomst. Specifikationen angiver ikke, at id ‘ et vil blive genereret med det samme, uanset id-generationsstrategien. Specifikationen for persistate-metoden gør det muligt for implementeringen at udstede udsagn til generering af id på commit eller flush, og id ‘ et garanteres ikke at være ikke-null efter at have kaldt denne metode, så du bør ikke stole på det.

du kan kalde denne metode på en allerede vedvarende forekomst, og der sker ikke noget. Men hvis du forsøger at fortsætte en løsrevet instans, er implementeringen bundet til at kaste en undtagelse. I det følgende eksempel fortsætter vi enheden, udsætter den fra konteksten, så den løsnes, og prøv derefter at fortsætte igen. Det andet opkald til session.vedvarende () forårsager en undtagelse, så følgende kode fungerer ikke:

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

3.2. Gem

Gem-metoden er en “original” dvaletilstand, der ikke er i overensstemmelse med JPA-specifikationen.

dens formål er stort set det samme som vedvarende, men det har forskellige implementeringsdetaljer. Dokumentationen for denne metode angiver strengt, at den fortsætter forekomsten, “først tildele en genereret identifikator”. Metoden er garanteret at returnere den Serialiserbare værdi af denne identifikator.

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

effekten af at gemme en allerede vedvarende forekomst er den samme som med vedvarende. Forskellen kommer, når du forsøger at gemme en løsrevet instans:

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

ID2-variablen vil afvige fra id1. Call of save på en løsrevet instans opretter en ny vedvarende instans og tildeler den en ny identifikator, hvilket resulterer i en duplikatpost i en database ved at begå eller skylle.

3.3. Flet

hovedformålet med fletningsmetoden er at opdatere en vedvarende enhedsinstans med nye feltværdier fra en løsrevet enhedsinstans.

Antag for eksempel, at du har en afslappende grænseflade med en metode til at hente et JSON-serialiseret objekt ved dets id til den, der ringer op, og en metode, der modtager en opdateret version af dette objekt fra den, der ringer op. En enhed, der passerede gennem en sådan serialisering/deserialisering, vises i en løsrevet tilstand.

efter deserialisering af denne enhedsinstans skal du hente en vedvarende enhedsinstans fra en persistenskontekst og opdatere dens felter med nye værdier fra denne løsrevne instans. Så fletningsmetoden gør netop det:

  • finder en enhedsinstans efter id taget fra det overførte objekt (enten hentes en eksisterende enhedsinstans fra persistenskonteksten eller en ny forekomst indlæst fra databasen);
  • kopierer felter fra det overførte objekt til denne forekomst;
  • returnerer nyligt opdateret forekomst.

i det følgende eksempel udskyder vi (løsner) den gemte enhed fra kontekst, ændrer feltet Navn og fletter derefter den løsrevne enhed.

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

Bemærk, at fletningsmetoden returnerer et objekt — det er mergedPerson-objektet, der blev indlæst i persistenskontekst og opdateret, ikke det personobjekt, du passerede som et argument. Det er to forskellige objekter, og personobjektet skal normalt kasseres (alligevel skal du ikke regne med, at det er knyttet til vedholdenhedskontekst).

som med vedvarende metode er fletningsmetoden specificeret af JSR-220 for at have visse semantik, som du kan stole på:

  • hvis enheden er løsrevet, kopieres den på en eksisterende persistent enhed;
  • hvis enheden er forbigående, kopieres den på en nyoprettet persistent enhed;
  • denne operation kaskader for alle relationer med cascade=MERGE eller cascade=all mapping;
  • hvis enheden er persistent, har dette metodekald ikke effekt på det (men cascading finder stadig sted).

3.4. Opdatering

som med vedvarende og gem, er opdateringsmetoden en “original” dvaletilstand, der var til stede længe før fletningsmetoden blev tilføjet. Dens semantik adskiller sig i flere nøglepunkter:

  • det virker på bestået objekt (dets returtype er ugyldig); opdateringsmetoden overgår det overførte objekt fra løsrevet til vedvarende tilstand;
  • denne metode kaster en undtagelse, hvis du videregiver det til en forbigående enhed.

i det følgende eksempel gemmer vi objektet, udsætter (løsner) det fra konteksten, ændrer derefter dets navn og kalder opdatering. Bemærk, at vi ikke placerer resultatet af opdateringsoperationen i en separat variabel, fordi opdateringen finder sted på selve personobjektet. Grundlæggende vedhæfter vi den eksisterende enhedsinstans til persistenskonteksten — noget JPA-specifikationen ikke tillader os at gøre.

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

forsøg på at ringe opdatering på en forbigående forekomst vil resultere i en undtagelse. Følgende fungerer ikke:

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

3.5. SaveOrUpdate

denne metode vises kun i Hibernate API og har ikke sin standardiserede modstykke. I lighed med opdatering kan den også bruges til genmontering af forekomster.

faktisk er den interne DefaultUpdateEventListener-klasse, der behandler opdateringsmetoden, en underklasse af DefaultSaveOrUpdateListener, der bare tilsidesætter nogle funktioner. Den største forskel ved saveOrUpdate-metoden er, at den ikke kaster undtagelse, når den anvendes på en forbigående forekomst; i stedet, det gør denne forbigående forekomst vedvarende. Følgende kode vil fortsætte en nyoprettet forekomst af Person:

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

du kan tænke på denne metode som et universelt værktøj til at gøre et objekt vedvarende uanset dets tilstand, uanset om det er forbigående eller løsrevet.

Hvad skal man bruge?

hvis du ikke har nogen særlige krav, skal du som tommelfingerregel holde dig til vedvarende og flettede metoder, fordi de er standardiserede og garanteret i overensstemmelse med JPA-specifikationen.

de er også bærbare, hvis du beslutter dig for at skifte til en anden persistensudbyder, men de kan undertiden ikke virke så nyttige som de “originale” Dvalemetoder, Gem, Opdater og gemorupdate.

konklusion

vi har diskuteret formålet med forskellige Dvalesessionsmetoder i forhold til styring af vedvarende enheder i runtime. Vi har lært, hvordan disse metoder transist enhed forekomster gennem deres livscyklus, og hvorfor nogle af disse metoder har duplikeret funktionalitet.



+