Odstraňovanie objektov pomocou režimu dlhodobého spánku

1. Prehľad

Ako plnohodnotný rámec ORM je Hibernate zodpovedný za správu životného cyklu perzistentných objektov (entít) vrátane operácií CRUD ako napr. čítať, uložiť, aktualizovať a vymazať.

V tomto článku skúmame rôzne spôsoby, ako je možné vymazať objekty z databázy pomocou režimu dlhodobého spánku a vysvetľujeme bežné problémy a úskalia, ktoré sa môžu vyskytnúť.

Používame JPA a iba krok späť a používame natívne API Hibernate pre tie funkcie, ktoré nie sú štandardizované v JPA.

2. Rôzne spôsoby mazania objektov

Objekty môžu byť vymazané v nasledujúcich scenároch:

  • Používaním EntityManager.odstrániť
  • Keď je odstránenie kaskádové z iných inštančných inštancií
  • Keď sa orphanRemoval sa aplikuje
  • Vykonaním a vymazať Vyhlásenie JPQL
  • Vykonaním natívnych dotazov
  • Aplikáciou techniky mäkkého delécie (filtrovanie entít s mäkkým odstránením podľa podmienky v @Kde doložka)

Vo zvyšnej časti článku sa podrobne zaoberáme týmito bodmi.

3. Vymazanie pomocou správcu entít

Vymazanie pomocou EntityManager je najpriamejší spôsob odstránenia inštancie entity:

Foo foo = nový Foo ("foo"); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); assertThat (foo, notNullValue ()); entityManager.remove (foo); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ()); 

V príkladoch v tomto článku používame pomocnú metódu na vyprázdnenie a vyčistenie kontextu perzistencie, keď je to potrebné:

void flushAndClear () {entityManager.flush (); entityManager.clear (); }

Po zavolaní na EntityManager.odstrániť metódou, dodaná inštancia prechádza na odstránený stav a s tým spojené vymazanie z databázy nastane pri nasledujúcom vyprázdnení.

Poznač si to odstránená inštancia sa znova zachová, ak a PERSISTA sa na ňu uplatňuje operácia. Častou chybou je ignorovanie toho, že a PERSISTA operácia bola použitá na odstránenú inštanciu (zvyčajne preto, že je kaskádovaná z inej inštancie v čase vyprázdňovania), pretože sekcia 3.2.2 špecifikácie Spoločného parlamentného zhromaždenia nariaďuje, aby sa v takom prípade opätovne trvala.

Ilustrujeme to definíciou a @ManyToOne združenie od Foo do Bar:

@Entity verejná trieda Foo {@ManyToOne (fetch = FetchType.LAZY, cascade = CascadeType.ALL) súkromný bar; // ďalšie mapovania, getre a setre}

Keď odstránime a Bar inštancia, na ktorú odkazuje a Foo inštancia, ktorá je tiež načítaná v kontexte perzistencie, Bar inštancia nebude odstránená z databázy:

Bar bar = nový Bar ("bar"); Foo foo = nový Foo ("foo"); foo.setBar (bar); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); bar = entityManager.find (Bar.class, bar.getId ()); entityManager.remove (bar); flushAndClear (); bar = entityManager.find (Bar.class, bar.getId ()); assertThat (bar, notNullValue ()); foo = entityManager.find (Foo.class, foo.getId ()); foo.setBar (null); entityManager.remove (bar); flushAndClear (); assertThat (entityManager.find (Bar.class, bar.getId ()), nullValue ());

Ak je odstránený Bar odkazuje a Foo, PERSISTA prevádzka je kaskádová od Foo do Bar pretože asociácia je označená cascade = CascadeType.ALL a vymazanie nie je naplánované. Aby sme overili, že sa to deje, môžeme povoliť úroveň protokolu sledovania pre org.hibernovať balíček a vyhľadajte položky ako zrušenie plánovania vymazania entity.

4. Kaskádové vymazanie

Odstránenie je možné kaskádovať do detských entít po odstránení rodičov:

Bar bar = nový Bar ("bar"); Foo foo = nový Foo ("foo"); foo.setBar (bar); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); entityManager.remove (foo); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ()); assertThat (entityManager.find (Bar.class, bar.getId ()), nullValue ());

Tu bar je odstránený, pretože odstránenie je kaskádové z foo, pretože združenie je deklarované ako kaskáda všetkých operácií životného cyklu od Foo do Bar.

Poznač si to je to takmer vždy chyba, ktorá sa kaskáduje ODSTRÁNIŤ prevádzka v a @ManyToMany združenie, pretože by to spustilo odstránenie podradených inštancií, ktoré môžu byť spojené s inými nadradenými inštanciami. To platí aj pre CascadeType.ALL, pretože to znamená, že všetky operácie majú byť kaskádové, vrátane ODSTRÁNIŤ prevádzka.

5. Odstránenie sirôt

The orphanRemoval direktíva deklaruje, že inštancie pridružených entít sa majú odstrániť, keď sú odpojené od nadradeného objektu, alebo ekvivalentne, keď je nadradený objekt odstránený.

Ukazujeme to definovaním takejto asociácie od Bar do Baz:

@Entity verejná trieda Bar {@OneToMany (cascade = CascadeType.ALL, orphanRemoval = true) private List bazList = new ArrayList (); // ďalšie mapovania, getre a setre}

Potom Baz inštancia sa automaticky odstráni, keď sa odstráni zo zoznamu rodiča Bar inštancia:

Bar bar = nový Bar ("bar"); Baz baz = nový Baz („baz“); bar.getBazList (). add (baz); entityManager.persist (lišta); flushAndClear (); bar = entityManager.find (Bar.class, bar.getId ()); baz = bar.getBazList (). get (0); bar.getBazList (). remove (baz); flushAndClear (); assertThat (entityManager.find (Baz.class, baz.getId ()), nullValue ());

Sémantika orphanRemoval prevádzka je úplne podobná a ODSTRÁNIŤ operácia aplikovaná priamo na inštancie postihnutého dieťaťa, čo znamená, že ODSTRÁNIŤ operácia sa ďalej kaskáduje k vnoreným deťom. V dôsledku toho musíte zabezpečiť, aby žiadne iné inštancie neodkazovali na odstránené (inak sa znova zachovajú).

6. Vymazanie pomocou vyhlásenia JPQL

Hibernate podporuje operácie odstránenia v štýle DML:

Foo foo = nový Foo ("foo"); entityManager.persist (foo); flushAndClear (); entityManager.createQuery ("delete from Foo where id =: id") .setParameter ("id", foo.getId ()) .executeUpdate (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

Je dôležité si to uvedomiť Príkazy JPQL v štýle DML neovplyvňujú stav ani životný cyklus inštancií entít, ktoré sú už načítané do kontextu perzistencie, preto sa odporúča vykonať ich pred načítaním dotknutých entít.

7. Vymazanie pomocou natívnych dotazov

Niekedy sa musíme vrátiť k natívnym dotazom, aby sme dosiahli niečo, čo nie je podporované režimom dlhodobého spánku alebo je špecifické pre dodávateľa databázy. Môžeme tiež vymazať údaje z databázy pomocou natívnych dotazov:

Foo foo = nový Foo ("foo"); entityManager.persist (foo); flushAndClear (); entityManager.createNativeQuery ("odstrániť z FOO, kde ID =: id") .setParameter ("id", foo.getId ()) .executeUpdate (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

Pre natívne dotazy platí rovnaké odporúčanie ako pre príkazy v štýle JPA DML, t.j. natívne dotazy neovplyvňujú ani stav ani životný cyklus inštancií entít, ktoré sa načítajú do kontextu perzistencie pred vykonaním dotazov.

8. Mäkké odstránenie

Často nie je žiaduce odstraňovať údaje z databázy z dôvodu auditovania a uchovávania histórie. V takýchto situáciách môžeme použiť techniku ​​zvanú jemné odstránenie. V zásade iba označíme riadok ako odstránený a pri načítaní údajov ho odfiltrujeme.

Aby sa zabránilo mnohým nadbytočným podmienkam v kde klauzuly vo všetkých dotazoch, ktoré čítajú mäkko vymazateľné entity, program Hibernate poskytuje @Kde anotáciu, ktorú je možné umiestniť na entitu a ktorá obsahuje fragment SQL, ktorý sa automaticky pridáva k dotazom SQL generovaným pre túto entitu.

Na demonštráciu to pridáme @Kde anotácia a stĺpec s názvom VYMAZANÉ do Foo subjekt:

@Entity @Where (clause = "DELETED = 0") verejná trieda Foo {// ďalšie mapovania @Column (name = "DELETED") súkromné ​​celé číslo vymazané = 0; // getre a setre public void setDeleted () {this.deleted = 1; }}

Nasledujúci test potvrdzuje, že všetko funguje podľa očakávaní:

Foo foo = nový Foo ("foo"); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); foo.setDeleted (); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

9. Záver

V tomto článku sme sa zaoberali rôznymi spôsobmi, ako je možné údaje vymazať pomocou režimu dlhodobého spánku. Vysvetlili sme základné pojmy a niektoré osvedčené postupy. Predviedli sme tiež, ako možno ľahko vykonať jemné mazanie pomocou režimu dlhodobého spánku.

Implementácia tohto programu Vymazávanie objektov s programom Hibernate je k dispozícii na serveri Github. Toto je projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


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