Hibernácia životného cyklu entity

1. Prehľad

Každá entita hibernácie má prirodzene svoj životný cyklus v rámci - je buď v prechodnom, spravovanom, odpojenom alebo vymazanom stave.

Pochopenie týchto stavov na koncepčnej aj technickej úrovni je nevyhnutné pre správne používanie režimu dlhodobého spánku.

Ak sa chcete dozvedieť viac o rôznych metódach dlhodobého spánku, ktoré sa zaoberajú entitami, pozrite si jeden z našich predchádzajúcich tutoriálov.

2. Pomocné metódy

V celom tomto výučbe budeme neustále používať niekoľko pomocných metód:

  • HibernateLifecycleUtil.getManagedEntities (relácia) - použijeme ho na získanie všetkých spravovaných subjektov z a Relácia interný obchod
  • DirtyDataInspector.getDirtyEntities () - použijeme túto metódu na získanie zoznamu všetkých entít, ktoré boli označené ako „špinavé“
  • HibernateLifecycleUtil.queryCount (dopyt) - pohodlná metóda počet (*) dotaz proti vloženej databáze

Všetky vyššie uvedené pomocné metódy sú staticky importované kvôli lepšej čitateľnosti. Ich implementácie nájdete v projekte GitHub prepojenom na konci tohto článku.

3. Je to všetko o vytrvalosti

Predtým, ako sa dostaneme k téme životného cyklu entity, je potrebné najskôr pochopiť kontext vytrvalosti.

Jednoducho povedané kontext vytrvalosti sedí medzi kódom klienta a dátovým úložiskom. Je to pracovná oblasť, kde sa trvalé údaje konvertujú na entity, pripravené na čítanie a zmeny v kóde klienta.

Teoreticky vzaté, kontext vytrvalosti je implementácia modelu jednotky práce. Sleduje všetky načítané údaje, sleduje zmeny týchto údajov a je zodpovedný za prípadnú synchronizáciu akýchkoľvek zmien späť do databázy na konci obchodnej transakcie.

JPA EntityManager a režim dlhodobého spánku Session sú implementáciou kontext vytrvalosti koncepcia. V tomto článku budeme používať režim dlhodobého spánku Session reprezentovať kontext vytrvalosti.

Stav životného cyklu entity dlhodobého spánku vysvetľuje, ako je entita spojená s a kontext vytrvalosti, ako uvidíme ďalej.

4. Spravovaný subjekt

Spravovaná entita je reprezentácia riadku databázovej tabuľky (aj keď tento riadok v databáze ešte nemusí existovať).

To je spravované práve bežiacim Sessiona každá vykonaná zmena bude automaticky sledovaná a šírená do databázy.

The Session buď načíta entitu z databázy, alebo znova pripojí odpojenú entitu. Samostatným entitám sa budeme venovať v časti 5.

Pozrime sa na nejaký kód, aby sme získali vysvetlenie.

Naša vzorová aplikácia definuje jednu entitu, Futbalista trieda. Pri spustení inicializujeme úložisko údajov niekoľkými vzorovými údajmi:

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

Povedzme, že chceme zmeniť meno Buffona na začiatok - chceme uviesť jeho celé meno Gianluigi Buffon namiesto Gigi Buffon.

Najskôr musíme zahájiť našu jednotku práce získaním a Relácia:

Relácia session = sessionFactory.openSession ();

V prostredí servera môžeme vložiť a Session do nášho kódu prostredníctvom kontextového proxy. Princíp zostáva rovnaký: potrebujeme a Session zapuzdriť obchodnú transakciu našej pracovnej jednotky.

Ďalej poučíme našich Session načítať údaje z trvalého úložiska:

assertThat (getManagedEntities (relácia)). isEmpty (); Zoznam hráčov = s.createQuery ("z FootballPlayer"). GetResultList (); assertThat (getManagedEntities (relácia)). size (). isEqualTo (3); 

Keď prvýkrát získame a Session, jeho trvalý kontextový obchod je prázdny, ako ukazuje náš prvý tvrdiť vyhlásenie.

Ďalej vykonávame dopyt, ktorý načíta údaje z databázy, vytvorí reprezentáciu údajov entity a nakoniec vráti entitu, ktorú môžeme použiť.

Vnútorne Session sleduje všetky načítané entity v trvalom kontextovom úložisku. V našom prípade Relácia interný obchod bude po dotaze obsahovať 3 entity.

Teraz si zmeňme Gigi meno:

Transakčná transakcia = session.getTransaction (); transaction.begin (); FootballPlayer gigiBuffon = players.stream () .filter (p -> p.getId () == 3) .findFirst () .get (); gigiBuffon.setName ("Gianluigi Buffon"); transaction.commit (); assertThat (getDirtyEntities ()). size (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Gianluigi Buffon");

4.1. Ako to funguje?

Na výzvu k transakcii spáchať () alebo spláchnuť(), Session nájdu akékoľvek špinavý entity zo svojho sledovacieho zoznamu a synchronizujú stav do databázy.

Všimnite si, že na oznámenie nemusíme volať nijakou metódou Session že sme niečo zmenili v našej entite - keďže ide o spravovanú entitu, všetky zmeny sa do databázy rozšíria automaticky.

Spravovaná entita je vždy perzistentná entita - musí mať identifikátor databázy, aj keď reprezentácia riadku databázy ešte nie je vytvorená, t. J. Príkaz INSERT čaká na koniec jednotky práce.

Nižšie nájdete kapitolu o prechodných entitách.

5. Samostatne stojaci subjekt

A detašovaný subjekt je len obyčajný subjekt POJO ktorého hodnota identity zodpovedá riadku databázy. Rozdiel od spravovanej entity je v tom, že je už nikto nesleduje kontext vytrvalosti.

Jednotka sa môže oddeliť, keď Session používané na načítanie bolo zatvorené, alebo keď voláme Session.evict (entity) alebo Session.clear ().

Pozrime sa na to v kóde:

FootballPlayer cr7 = session.get (FootballPlayer.class, 1L); assertThat (getManagedEntities (relácia)). size (). isEqualTo (1); assertThat (getManagedEntities (relácia) .get (0) .getId ()). isEqualTo (cr7.getId ()); session.evict (cr7); assertThat (getManagedEntities (relácia)). size (). isEqualTo (0);

Náš kontext vytrvalosti nebude sledovať zmeny v oddelených entitách:

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

Session.merge (entita) /Session.update (entita) môže (znovu) pripojiť reláciu:

FootballPlayer messi = session.get (FootballPlayer.class, 2L); session.evict (messi); messi.setName ("Leo Messi"); transaction.commit (); assertThat (getDirtyEntities ()). isEmpty (); transakcia = startTransaction (relácia); session.update (messi); transaction.commit (); assertThat (getDirtyEntities ()). size (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Leo Messi");

Pre porovnanie na oboch Session.merge () a Session.update () pozri tu.

5.1. Na poli identity záleží

Pozrime sa na nasledujúcu logiku:

FootballPlayer gigi = nový FootballPlayer (); gigi.setId (3); gigi.setName ("Legenda Gigi"); session.update (gigi);

Vo vyššie uvedenom príklade sme entitu vytvorili obvyklým spôsobom prostredníctvom jej konštruktora. Vyplnili sme polia hodnotami a nastavili sme identitu na 3, čo zodpovedá identite perzistentných údajov patriacich Gigi Buffonovi. Telefonovanie aktualizácia () má úplne rovnaký efekt, ako keby sme entitu načítali z iného kontext vytrvalosti.

V skutočnosti, Session nerozlišuje, odkiaľ pochádza znovu pripojená entita.

Je to úplne bežný scenár vo webových aplikáciách na zostavenie oddelených entít z hodnôt formulárov HTML.

Pokiaľ Session pokiaľ ide o, odpojená entita je iba obyčajná entita, ktorej hodnota identity zodpovedá trvalým údajom.

Uvedomte si, že vyššie uvedený príklad slúži iba na demonštračné účely. a potrebujeme presne vedieť, čo robíme. V opačnom prípade by sme mohli skončiť s nulovými hodnotami v celej našej entite, keby sme iba nastavili hodnotu na pole, ktoré chceme aktualizovať, a zvyšok by sme nechali nedotknutý (teda v skutočnosti nulový).

6. Prechodná entita

Prechodná entita je jednoducho subjekt objekt, ktorý nemá v perzistentnom úložisku žiadne zastúpenie a nie je spravovaný žiadnym Session.

Typickým príkladom prechodnej entity by bolo vytvorenie inštancie novej entity prostredníctvom jej konštruktora.

Vytvoriť prechodnú entitu vytrvalý, musíme zavolať Session.save (entita) alebo Session.saveOrUpdate (entita):

FootballPlayer neymar = nový FootballPlayer (); neymar.setName ("Neymar"); session.save (neymar); assertThat (getManagedEntities (relácia)). size (). isEqualTo (1); assertThat (neymar.getId ()). isNotNull (); int count = queryCount ("vyberte počet (*) z Football_Player, kde name =" Neymar ""); assertThat (count) .isEqualTo (0); transaction.commit (); count = queryCount ("vyberte count (*) z Football_Player kde name =" Neymar ""); assertThat (count) .isEqualTo (1);

Hneď ako vykonáme Session.save (entita), je entite pridelená hodnota identity a stáva sa spravovanou Session. Zatiaľ to však nemusí byť v databáze k dispozícii, pretože operácia INSERT sa môže oneskoriť až do konca jednotky práce.

7. Vymazaná entita

Entita je v odstránenom (odstránenom) stave, ak Session.delete (entita) bol povolaný a Session označil subjekt na odstránenie. Samotný príkaz DELETE môže byť vydaný na konci pracovnej jednotky.

Pozrime sa na to v nasledujúcom kóde:

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

Všimnite si však, že entita zostáva v pretrvávajúcom kontextovom úložisku až do konca jednotky práce.

8. Záver

Koncepcia kontext vytrvalosti je kľúčové pre pochopenie životného cyklu entít režimu dlhodobého spánku. Životný cyklus sme objasnili preskúmaním príkladov kódu demonštrujúcich každý stav.

Ako obvykle, kód použitý v tomto článku nájdete na GitHub.


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