Dvalemodus Enhets livssyklus

1. Oversikt

Hver dvaleenhet har naturlig nok en livssyklus innenfor rammene - den er enten i en forbigående, administrert, løsrevet eller slettet tilstand.

Å forstå disse tilstandene på både konseptuelt og teknisk nivå er viktig for å kunne bruke dvalemodus riktig.

Hvis du vil lære om forskjellige dvalemetoder som omhandler enheter, kan du ta en titt på en av våre tidligere opplæringsprogrammer.

2. Hjelpemetoder

Gjennom denne opplæringen bruker vi konsekvent flere hjelpemetoder:

  • HibernateLifecycleUtil.getManagedEntities (økt) - vi bruker den til å få alle administrerte enheter fra a Økten er intern butikk
  • DirtyDataInspector.getDirtyEntities () - vi skal bruke denne metoden for å få en liste over alle enheter som ble merket som 'skitne'
  • HibernateLifecycleUtil.queryCount (spørring) - en praktisk metode å gjøre telle(*) spørring mot den innebygde databasen

Alle de ovennevnte hjelpemetodene importeres statisk for bedre lesbarhet. Du finner implementeringene deres i GitHub-prosjektet som er koblet på slutten av denne artikkelen.

3. Det handler om utholdenhetskontekst

Før vi begynner å gå inn i temaet livssyklus for enheter, må vi forstå det utholdenhetskonteksten.

Enkelt sagt, den utholdenhetskontekst sitter mellom klientkode og datalager. Det er et iscenesettelsesområde der vedvarende data konverteres til enheter, klare til å bli lest og endret av klientkode.

Teoretisk sett er utholdenhetskontekst er en implementering av arbeidsmodellen. Den holder rede på alle lastede data, sporer endringer av disse dataene, og er ansvarlig for til slutt å synkronisere eventuelle endringer tilbake til databasen på slutten av forretningstransaksjonen.

JPA EntityManager og dvalemodus Økt er en implementering av utholdenhetskontekst konsept. Gjennom denne artikkelen vil vi bruke dvalemodus Økt å representere utholdenhetskontekst.

Dvalemodusenhetens livssyklusstatus forklarer hvordan enheten er relatert til en utholdenhetskontekst, som vi får se neste.

4. Administrert enhet

En administrert enhet er en representasjon av en databasetabellrad (selv om den raden ikke trenger å eksistere i databasen ennå).

Dette styres av den som kjører Økt, og hver endring som blir gjort på den, blir automatisk sporet og overført til databasen.

De Økt enten laster enheten fra databasen eller legger ved en frittliggende enhet på nytt. Vi vil diskutere frittliggende enheter i avsnitt 5.

La oss observere noen koder for å få avklaring.

Eksempelapplikasjonen vår definerer en enhet, Fotballspiller klasse. Ved oppstart initialiserer vi datalageret med noen eksempeldata:

+ ------------------- + ------- + | Navn | ID | + ------------------- + ------- + | Cristiano Ronaldo | 1 | | Lionel Messi | 2 | | Gianluigi Buffon | 3 | + ------------------- + ------- +

La oss si at vi vil endre navnet på Buffon til å begynne med - vi vil sette inn hans fulle navn Gianluigi Buffon i stedet for Gigi Buffon.

Først må vi starte vår arbeidsenhet ved å skaffe oss en Økt:

Sessionsøkt = sessionFactory.openSession ();

I et servermiljø kan vi injisere en Økt til koden vår via en kontekstbevisst proxy. Prinsippet forblir det samme: vi trenger a Økt for å kapsle inn forretningstransaksjonen til vår arbeidsenhet.

Deretter instruerer vi vår Økt for å laste inn dataene fra den vedvarende butikken:

assertThat (getManagedEntities (økt)). er tom (); Liste spillere = s.createQuery ("fra FootballPlayer"). GetResultList (); assertThat (getManagedEntities (session)). størrelse (). isEqualTo (3); 

Når vi først får en Økt, den vedvarende kontekstbutikken er tom, som vist av vår første hevder uttalelse.

Deretter utfører vi et spørsmål som henter data fra databasen, oppretter enhetsrepresentasjon av dataene og til slutt returnerer enheten som vi kan bruke.

Internt, den Økt holder oversikt over alle enheter den lastes inn i den vedvarende kontekstbutikken. I vårt tilfelle er Økten er intern butikk vil inneholde 3 enheter etter spørringen.

La oss nå endre Gigis navn:

Transaksjonstransaksjon = session.getTransaction (); transaction.begin (); FootballPlayer gigiBuffon = players.stream () .filter (p -> p.getId () == 3) .findFirst () .get (); gigiBuffon.setName ("Gianluigi Buffon"); transaction.commit (); assertThat (getDirtyEntities ()). størrelse (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Gianluigi Buffon");

4.1. Hvordan virker det?

På oppfordring til transaksjon begå() eller flush (), den Økt vil finne noen skitten enheter fra sporingslisten og synkroniserer tilstanden til databasen.

Legg merke til at vi ikke trengte å ringe noen metode for å varsle Økt at vi endret noe i enheten vår - siden det er en administrert enhet, overføres alle endringer til databasen automatisk.

En administrert enhet er alltid en vedvarende enhet - den må ha en databaseidentifikator, selv om databaseradrepresentasjonen ennå ikke er opprettet, dvs. INSERT-setningen venter på slutten av arbeidsenheten.

Se kapittelet om forbigående enheter nedenfor.

5. Frittliggende enhet

EN frittliggende enhet er bare en vanlig enhet POJO hvis identitetsverdi tilsvarer en databaserad. Forskjellen fra en administrert enhet er at den er ikke spores lenger av noen utholdenhetskontekst.

En enhet kan løsrive seg når Økt brukes til å laste den var stengt, eller når vi ringer Session.evict (enhet) eller Session.clear ().

La oss se det i koden:

FootballPlayer cr7 = session.get (FootballPlayer.class, 1L); assertThat (getManagedEntities (session)). størrelse (). isEqualTo (1); assertThat (getManagedEntities (session) .get (0) .getId ()). isEqualTo (cr7.getId ()); session.evict (cr7); assertThat (getManagedEntities (session)). størrelse (). isEqualTo (0);

Vår utholdenhetskontekst vil ikke spore endringene i frittliggende enheter:

cr7.setName ("CR7"); transaction.commit (); assertThat (getDirtyEntities ()). er Empty ();

Session.merge (entity) / Session.update (entity) kan (re) legge til en økt:

FootballPlayer messi = session.get (FootballPlayer.class, 2L); session.evict (messi); messi.setName ("Leo Messi"); transaction.commit (); assertThat (getDirtyEntities ()). er Empty (); transaksjon = startTransaksjon (økt); session.update (messi); transaction.commit (); assertThat (getDirtyEntities ()). størrelse (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Leo Messi");

For referanse på begge deler Session.merge () og Session.update () se her.

5.1. Identitetsfeltet er alt som betyr noe

La oss ta en titt på følgende logikk:

FootballPlayer gigi = ny FootballPlayer (); gigi.setId (3); gigi.setName ("Gigi the Legend"); session.update (gigi);

I eksemplet ovenfor har vi instantiert en enhet på vanlig måte via sin konstruktør. Vi har fylt ut feltene med verdier, og vi har satt identiteten til 3, som tilsvarer identiteten til vedvarende data som tilhører Gigi Buffon. Ringer Oppdater() har nøyaktig samme effekt som om vi har lastet enheten fra en annen utholdenhetskontekst.

Faktisk, Økt skiller ikke ut hvor en tilknyttet enhet stammer fra.

Det er ganske vanlig i webapplikasjoner å konstruere frittliggende enheter fra HTML-skjemaverdier.

Så langt som Økt er bekymret, er en frittliggende enhet bare en ren enhet hvis identitetsverdi tilsvarer vedvarende data.

Vær oppmerksom på at eksemplet ovenfor bare tjener et demo-formål. og vi trenger å vite nøyaktig hva vi gjør. Ellers kan vi ende opp med nullverdier på tvers av enheten vår hvis vi bare setter verdien på feltet vi vil oppdatere, slik at resten blir uberørt (så faktisk null).

6. Forbigående enhet

En forbigående enhet er rett og slett en enhet objekt som ikke har noen representasjon i den vedvarende butikken og administreres ikke av noen Økt.

Et typisk eksempel på en forbigående enhet ville være å starte en ny enhet via sin konstruktør.

Å lage en forbigående enhet vedvarende, vi må ringe Session.save (enhet) eller Session.saveOrUpdate (enhet):

FootballPlayer neymar = ny FootballPlayer (); neymar.setName ("Neymar"); session.save (neymar); assertThat (getManagedEntities (session)). størrelse (). isEqualTo (1); assertThat (neymar.getId ()). erNotNull (); int count = queryCount ("select count (*) from Football_Player where name =" Neymar ""); assertThat (count) .isEqualTo (0); transaction.commit (); count = queryCount ("select count (*) from Football_Player where name =" Neymar ""); assertThat (count) .isEqualTo (1);

Så snart vi kjører Session.save (enhet), blir enheten tildelt en identitetsverdi og blir administrert av Økt. Imidlertid er det kanskje ikke tilgjengelig i databasen ennå, da INSERT-operasjonen kan bli forsinket til slutten av arbeidsenheten.

7. Slettet enhet

En enhet er i en slettet (fjernet) tilstand hvis Session.delete (enhet) har blitt kalt, og Økt har merket enheten for sletting. Selve DELETE-kommandoen kan bli utstedt på slutten av arbeidsenheten.

La oss se det i følgende kode:

session.delete (neymar); assertThat (getManagedEntities (session) .get (0) .getStatus ()). isEqualTo (Status.DELETED);

Legg imidlertid merke til at enheten forblir i den vedvarende kontekstbutikken til slutten av arbeidsenheten.

8. Konklusjon

Konseptet av utholdenhetskontekst er sentralt for å forstå livssyklusen til dvalemodusenheter. Vi har avklart livssyklusen ved å se på kodeeksemplene som viser hver status.

Som vanlig kan koden som brukes i denne artikkelen finnes på GitHub.


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