Dvalemodus: lagre, vedvare, oppdatere, slå sammen, lagreOrUpdate

1. Introduksjon

I denne artikkelen vil vi diskutere forskjellene mellom flere metoder for Økt grensesnitt: lagre, fortsette, Oppdater, slå sammen, saveOrUpdate.

Dette er ikke en introduksjon til dvalemodus, og du bør allerede vite det grunnleggende om konfigurasjon, objektrelasjonell kartlegging og arbeid med enhetsforekomster. For en innledende artikkel om dvalemodus, besøk vår veiledning om dvalemodus 4 med våren.

2. Session as a Persistence Context Implementation

De Økt grensesnittet har flere metoder som til slutt resulterer i lagring av data i databasen: fortsette, lagre, Oppdater, slå sammen, saveOrUpdate. For å forstå forskjellen mellom disse metodene, må vi først diskutere formålet med Økt som en utholdenhetskontekst og forskjellen mellom tilstandene til entitetsforekomster i forhold til Økt.

Vi bør også forstå historien til dvalemodusutviklingen som førte til noen delvis dupliserte API-metoder.

2.1. Administrere enhetsforekomster

Bortsett fra selve objektrelasjonskartleggingen, er et av problemene som dvalemodus var ment å løse, problemet med å administrere enheter under kjøretid. Begrepet "utholdenhetskontekst" er Hibernates løsning på dette problemet. Persistens-kontekst kan betraktes som en container eller et første nivå hurtigbuffer for alle objektene du lastet eller lagret i en database under en økt.

Økten er en logisk transaksjon, hvilke grenser er definert av applikasjonens forretningslogikk. Når du arbeider med databasen gjennom en utholdenhetskontekst, og alle enhetens forekomster er knyttet til denne konteksten, bør du alltid ha en enkelt forekomst av enhet for hver databaseoppføring du har samhandlet under økten med.

I dvalemodus er utholdenhetskonteksten representert med org.hibernate.Session forekomst. For JPA er det javax.persistence.EntityManager. Når vi bruker Hibernate som JPA-leverandør og opererer via EntityManager grensesnitt, implementerer dette grensesnittet i utgangspunktet det underliggende Økt gjenstand. Imidlertid dvale Økt gir et rikere grensesnitt med flere muligheter, så noen ganger er det nyttig å jobbe med Økt direkte.

2.2. Forekomster av stater

Enhver enhetsforekomst i søknaden din vises i en av de tre hovedstatene i forhold til Økt utholdenhetskontekst:

  • flyktig - denne forekomsten er ikke, og ble aldri, knyttet til en Økt; denne forekomsten har ingen tilsvarende rader i databasen; det er vanligvis bare et nytt objekt du har opprettet for å lagre i databasen;
  • vedvarende - denne forekomsten er assosiert med en unik Økt gjenstand; ved spyling av Økt til databasen, er denne enheten garantert å ha en tilsvarende konsistent post i databasen;
  • frakoblet - denne forekomsten var en gang knyttet til en Økt (i en vedvarende tilstand), men nå er det ikke; en forekomst går inn i denne tilstanden hvis du kaster den ut av konteksten, tømmer eller lukker økten, eller setter forekomsten gjennom serieiserings- / deserialiseringsprosessen.

Her er et forenklet tilstandsdiagram med kommentarer til Økt metoder som får statsovergangene til å skje.

Når enhetens forekomst er i vedvarende tilstand, vil alle endringer du gjør i de tilordnede feltene i denne forekomsten, bli brukt på de tilsvarende databaseregistreringene og -feltene når du skyller Økt. De vedvarende forekomst kan betraktes som "online", mens frakoblet forekomst har gått "offline" og overvåkes ikke for endringer.

Dette betyr at når du endrer felt i a vedvarende objekt, du trenger ikke å ringe lagre, Oppdater eller noen av disse metodene for å få disse endringene til databasen: alt du trenger er å begå transaksjonen, eller skylle eller lukke økten når du er ferdig med den.

2.3. Overensstemmelse med JPA-spesifikasjon

Dvalemodus var den mest vellykkede implementeringen av Java ORM. Ikke rart at spesifikasjonen for Java persistence API (JPA) ble sterkt påvirket av Hibernate API. Dessverre var det også mange forskjeller: noen store, noen mer subtile.

For å fungere som en implementering av JPA-standarden, måtte Hibernate API-er revideres. Flere metoder ble lagt til sesjonsgrensesnittet for å matche EntityManager-grensesnittet. Disse metodene tjener samme formål som de “originale” metodene, men samsvarer med spesifikasjonen og har dermed noen forskjeller.

3. Forskjeller mellom operasjonene

Det er viktig å forstå fra begynnelsen at alle metodene (fortsette, lagre, Oppdater, slå sammen, saveOrUpdate) ikke umiddelbart resultere i tilsvarende SQL OPPDATER eller SETT INN uttalelser. Den faktiske lagringen av data i databasen skjer ved å gjennomføre transaksjonen eller skylle Økt.

De nevnte metodene styrer i utgangspunktet tilstanden til entitetsforekomstene ved å overføre dem mellom forskjellige stater langs livssyklusen.

Som et eksempel på enhet, vil vi bruke en enkel annotasjonskartet enhet Person:

@Entity offentlig klasse Person {@Id @GeneratedValue private Lang id; privat strengnavn; // ... getters og setters}

3.1. Fortsette

De fortsette metoden er ment for å legge til en ny entitetsforekomst til utholdenhetskonteksten, dvs. overføre en forekomst fra forbigående til vedvarende stat.

Vi kaller det vanligvis når vi vil legge til en post i databasen (vedvarer en enhetsforekomst):

Personperson = ny person (); person.setName ("John"); session.persist (person);

Hva skjer etter fortsette metoden kalles? De person objektet har gått over fra flyktig til vedvarende stat. Objektet er i utholdenhetskontekst nå, men ennå ikke lagret i databasen. Generasjonen av SETT INN uttalelser vil bare skje når du begår transaksjonen, skyller eller avslutter økten.

Legg merke til at fortsette metoden har tomrom returtype. Den opererer på det passerte objektet "på plass" og endrer tilstanden. De person variabel refererer til det faktiske vedvarende objektet.

Denne metoden er et senere tillegg til sesjonsgrensesnittet. Det viktigste skilletrekk ved denne metoden er at den er i samsvar med JSR-220-spesifikasjonen (EJB-utholdenhet). Semantikken til denne metoden er strengt definert i spesifikasjonen, som i utgangspunktet sier at:

  • en flyktig forekomst blir vedvarende (og operasjonen faller inn i alle dens forhold til kaskade = PERSIST eller kaskade = ALLE),
  • hvis en forekomst allerede er vedvarende, så har denne samtalen ingen effekt for denne spesielle saken (men den faller fremdeles i forholdet til kaskade = PERSIST eller kaskade = ALLE),
  • hvis en forekomst er det frakoblet, kan du forvente et unntak, enten når du kaller denne metoden, eller når du begår eller skyller økten.

Legg merke til at det ikke er noe her som gjelder identifikatoren for en forekomst. Spesifikasjonen angir ikke at id vil bli generert med en gang, uavhengig av strategi for generering av id. Spesifikasjonen for fortsette metoden tillater implementeringen å utstede uttalelser for å generere id ved commit eller flush, og id er ikke garantert at den ikke er null etter at du har kalt denne metoden, så du bør ikke stole på den.

Du kan kalle denne metoden på en allerede vedvarende eksempel, og ingenting skjer. Men hvis du prøver å vedvare a frakoblet eksempel, implementeringen er bundet til å kaste et unntak. I det følgende eksemplet vi fortsette enheten, kaste det fra konteksten slik at det blir frakoblet, og prøv deretter å fortsette en gang til. Den andre samtalen til session.persist () forårsaker et unntak, så følgende kode vil ikke fungere:

Personperson = ny person (); person.setName ("John"); session.persist (person); session.evict (person); session.persist (person); // PersistenceException!

3.2. Lagre

De lagre metoden er en "original" dvalemetode som ikke samsvarer med JPA-spesifikasjonen.

Hensikten er i utgangspunktet den samme som fortsette, men det har forskjellige implementeringsdetaljer. Dokumentasjonen for denne metoden sier strengt at den fortsetter forekomsten, "først tilordne en generert identifikator". Metoden returnerer garantert Serialiserbar verdien av denne identifikatoren.

Personperson = ny person (); person.setName ("John"); Lang id = (Lang) økt. Lagre (person);

Effekten av å lagre en allerede vedvarende forekomst er den samme som med fortsette. Forskjellen kommer når du prøver å lagre en frakoblet forekomst:

Personperson = ny person (); person.setName ("John"); Lang id1 = (Lang) økt. Lagre (person); session.evict (person); Lang id2 = (Lang) økt. Lagre (person);

De id2 variabel vil variere fra id1. Call of save på en frakoblet forekomst skaper en ny vedvarende forekomst og tildeler den en ny identifikator, noe som resulterer i en duplikatoppføring i en database ved forpliktelse eller spyling.

3.3. Slå sammen

Hovedintensjonen til slå sammen metoden er å oppdatere en vedvarende enhetsforekomst med nye feltverdier fra en frakoblet enhetsforekomst.

Anta for eksempel at du har et RESTful-grensesnitt med en metode for å hente et JSON-serieobjekt med ID til innringeren og en metode som mottar en oppdatert versjon av dette objektet fra innringeren. En enhet som har gått gjennom slik serialisering / deserialisering vil vises i en frakoblet stat.

Etter at du har deserisert denne enhetforekomsten, må du skaffe deg en vedvarende entitetsforekomst fra en utholdenhetskontekst og oppdater feltene med nye verdier fra dette frakoblet forekomst. Så slå sammen metoden gjør akkurat det:

  • finner en enhetsforekomst etter id hentet fra det passerte objektet (enten blir en eksisterende enhetsforekomst fra utholdenhetskonteksten hentet, eller en ny forekomst lastet fra databasen);
  • kopierer felt fra det passerte objektet til denne forekomsten;
  • returnerer nylig oppdatert forekomst.

I det følgende eksemplet vi kaste (løsne) den lagrede enheten fra sammenhengen, endre Navn felt, og deretter slå sammen de frakoblet enhet.

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

Merk at slå sammen metoden returnerer et objekt - det er fusjonertPerson objekt som ble lastet inn i utholdenhetskontekst og oppdatert, ikke person objektet du sendte som argument. Det er to forskjellige objekter, og person objektet må vanligvis kastes (uansett, ikke stole på at det er knyttet til utholdenhetskontekst).

Som med fortsette metoden, den slå sammen metoden er spesifisert av JSR-220 for å ha visse semantikk som du kan stole på:

  • hvis enheten er frakoblet, det kopieres på en eksisterende vedvarende enhet
  • hvis enheten er flyktig, det kopieres på en nyopprettet vedvarende enhet
  • denne operasjonen kaskader for alle relasjoner med kaskade = MERGE eller kaskade = ALLE kartlegging;
  • hvis enheten er vedvarende, så har ikke denne metodeanropet effekt på det (men kaskadingen foregår fortsatt).

3.4. Oppdater

Som med fortsette og lagre, den Oppdater metoden er en "original" dvalemetode som var til stede lenge før slå sammen metoden ble lagt til. Semantikken er forskjellig i flere viktige punkter:

  • den virker på passert objekt (dens returtype er tomrom); de Oppdater metoden overgår det passerte objektet fra frakoblet til vedvarende stat;
  • denne metoden kaster et unntak hvis du passerer den a flyktig enhet.

I det følgende eksemplet vi lagre objektet, da kaste (koble den fra konteksten, og endre deretter dens Navn og ring Oppdater. Legg merke til at vi ikke legger resultatet av Oppdater operasjon i en egen variabel, fordi Oppdater finner sted på person selve objektet. I utgangspunktet kobler vi den eksisterende enhetsforekomsten til vedvarende kontekst på nytt - noe JPA-spesifikasjonen ikke tillater oss å gjøre.

Personperson = ny person (); person.setName ("John"); session.save (person); session.evict (person); person.setName ("Mary"); session.update (person);

Prøver å ringe Oppdater på en flyktig forekomst vil resultere i et unntak. Følgende fungerer ikke:

Personperson = ny person (); person.setName ("John"); session.update (person); // PersistenceException!

3.5. Lagre eller oppdater

Denne metoden vises bare i Hibernate API og har ikke sin standardiserte motstykke. Lik Oppdater, det kan også brukes til å feste tilfeller på nytt.

Egentlig det indre StandardUpdateEventListener klasse som behandler Oppdater metoden er en underklasse av DefaultSaveOrUpdateListener, bare overstyre noen funksjonalitet. Hovedforskjellen på saveOrUpdate metoden er at den ikke kaster unntak når den brukes på en flyktig forekomst; i stedet gjør det dette flyktig forekomst vedvarende. Følgende kode vil vedvare en nylig opprettet forekomst av Person:

Personperson = ny person (); person.setName ("John"); session.saveOrUpdate (person);

Du kan tenke på denne metoden som et universelt verktøy for å lage et objekt vedvarende uavhengig av tilstanden den er flyktig eller frakoblet.

4. Hva skal jeg bruke?

Hvis du ikke har noen spesielle krav, som en tommelfingerregel, bør du holde deg til fortsette og slå sammen metoder, fordi de er standardiserte og garantert samsvarer med JPA-spesifikasjonen.

De er også bærbare i tilfelle du bestemmer deg for å bytte til en annen utholdenhetsleverandør, men de kan noen ganger virke ikke så nyttige som de "originale" dvalemetodene, lagre, Oppdater og saveOrUpdate.

5. Konklusjon

Vi har diskutert formålet med forskjellige Hibernate Session-metoder i forhold til å administrere vedvarende enheter i løpetid. Vi har lært hvordan disse metodene overgår entitetsforekomster gjennom livssyklusen, og hvorfor noen av disse metodene har duplisert funksjonalitet.

Kildekoden for artikkelen er tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found