Objektumok törlése hibernált állapotban

1. Áttekintés

Teljes körű ORM keretrendszerként a Hibernate felelős a tartós objektumok (entitások) életciklus-kezeléséért, beleértve a CRUD-műveleteket, mint pl. olvas, mentés, frissítés és töröl.

Ebben a cikkben különféle dolgokat tárunk fel az objektumok törlése az adatbázisból a hibernálás használatával és elmagyarázzuk a felmerülő gyakori kérdéseket és buktatókat.

A JPA-t használjuk, és csak visszalépünk, és a Hibernate natív API-t használjuk azokhoz a szolgáltatásokhoz, amelyek nincsenek szabványosítva a JPA-ban.

2. Az objektumok törlésének különböző módjai

Az objektumok a következő esetekben törölhetők:

  • Használva EntityManager.remove
  • Amikor egy törlés lép be más entitáspéldányokból
  • Amikor egy árvaRemoval alkalmazzák
  • Végrehajtással a töröl JPQL utasítás
  • Natív lekérdezések végrehajtásával
  • Lágy törlési technika alkalmazásával (a törölt entitások szűrése egy @Hol kikötés)

A cikk további részében részletesen megvizsgáljuk ezeket a pontokat.

3. Törlés az Entity Manager használatával

Törlés a EntityManager az entitáspéldány eltávolításának legegyszerűbb módja:

Foo foo = új Foo ("foo"); entityManager.persist (foo); flushAndClear (); foo = entitásManager.find (Foo.osztály, foo.getId ()); assertThat (foo, notNullValue ()); entitásManager.remove (foo); flushAndClear (); assertThat (entitásManager.find (Foo.osztály, foo.getId ()), nullValue ()); 

Az ebben a cikkben szereplő példákban segítő módszert használunk a kitartás kontextusának öblítésére és tisztítására, ha szükséges:

void flushAndClear () {entitásManager.flush (); entitásManager.clear (); }

Miután felhívta a EntityManager.remove metódus, a mellékelt példány áttér a eltávolítva állapot és a kapcsolódó törlés az adatbázisból a következő öblítéskor következik be.

Vegye figyelembe, hogy a törölt példány újra fennmarad, ha a PERSISTA műveletet alkalmaznak rá. Gyakori hiba, hogy figyelmen kívül hagyják, hogy a PERSISTA műveletet alkalmaztunk egy eltávolított példányra (általában azért, mert egy másik példánytól lépcsőzetes az öblítéskor), mert a szakasz 3.2.2 A JPA specifikációja előírja, hogy az ilyen esetet ilyen esetben újra fenn kell tartani.

Ezt úgy szemléltetjük, hogy meghatározzuk a @ManyToOne egyesület től Foo nak nek Rúd:

@Entity public class Foo {@ManyToOne (fetch = FetchType.LAZY, cascade = CascadeType.ALL) privát sáv; // egyéb leképezések, mérőeszközök és beállítók}

Amikor töröljük a Rúd a hivatkozott példány Foo a perzisztencia-kontextusban is betöltődő példány, a Rúd a példány nem kerül eltávolításra az adatbázisból:

Bár sáv = új sáv ("bár"); Foo foo = új Foo ("foo"); foo.setBar (bár); entityManager.persist (foo); flushAndClear (); foo = entitásManager.find (Foo.osztály, foo.getId ()); bar = entitásManager.find (Bar.osztály, bar.getId ()); entitásManager.remove (bar); flushAndClear (); bar = entitásManager.find (Bar.osztály, bar.getId ()); assertThat (bar, notNullValue ()); foo = entitásManager.find (Foo.osztály, foo.getId ()); foo.setBar (null); entitásManager.remove (bar); flushAndClear (); assertThat (entitásManager.find (Bar.osztály, bar.getId ()), nullValue ());

Ha az eltávolított Rúd hivatkozik a Foo, a PERSISTA művelet lépcsőzetes Foo nak nek Rúd mert az egyesületet jelöli kaszkád = CascadeType.ALL és a törlés ütemezés nélküli. Ennek ellenőrzéséhez engedélyezhetjük a nyomkövetési napló szintjét a org.hibernate csomagot és keressen olyan bejegyzéseket, mint pl ütemezés nélküli entitás törlése.

4. Lépcsőzetes törlés

A törlés a gyermekek entitásaiba léphet, ha a szülőket eltávolítják:

Bár sáv = új sáv ("bár"); Foo foo = új Foo ("foo"); foo.setBar (bár); entityManager.persist (foo); flushAndClear (); foo = entitásManager.find (Foo.osztály, foo.getId ()); entitásManager.remove (foo); flushAndClear (); assertThat (entitásManager.find (Foo.osztály, foo.getId ()), nullValue ()); assertThat (entitásManager.find (Bar.osztály, bar.getId ()), nullValue ());

Itt rúd eltávolításra kerül, mert az eltávolítás lépcsőzetes foo, mivel az asszociáció kijelentette, hogy az összes életciklus-műveletet kaszkádba veszi Foo nak nek Rúd.

Vegye figyelembe, hogy szinte mindig hiba a kaszkádban Távolítsa el művelet a @ManyToMany Egyesület, mert ez kiváltaná a szülőpéldányok eltávolítását, amelyek más szülőpéldányokkal társíthatók. Ez vonatkozik a CascadeType.ALL, mivel ez azt jelenti, hogy minden műveletet lépcsőzetesen kell végrehajtani, beleértve a Távolítsa el művelet.

5. Árvák eltávolítása

A árvaRemoval irányelv kimondja, hogy a társult entitás-példányokat el kell távolítani, ha el vannak választva a szülőtől, vagy ezzel egyenértékűen, ha a szülőt eltávolítják.

Ezt egy ilyen asszociáció meghatározásával mutatjuk be Rúd nak nek Baz:

@Entity public class Bar {@OneToMany (cascade = CascadeType.ALL, orphanRemoval = true) private List bazList = new ArrayList (); // egyéb leképezések, mérőeszközök és beállítók}

Aztán a Baz a példány automatikusan törlődik, amikor eltávolítja a szülő listájáról Rúd példa:

Bár sáv = új sáv ("bár"); Baz baz = új Baz ("baz"); bar.getBazList (). add (baz); entitásMenedzser.perszisztens (sáv); flushAndClear (); bar = entitásManager.find (Bar.osztály, bar.getId ()); baz = bar.getBazList (). get (0); bar.getBazList (). távolítsa el (baz); flushAndClear (); assertThat (entitásManager.find (Baz.osztály, baz.getId ()), nullValue ());

A szemantika a árvaRemoval a működés teljesen hasonló a Távolítsa el közvetlenül az érintett gyermekpéldányokra alkalmazott művelet, ami azt jelenti, hogy a Távolítsa el a művelet tovább lépcsőzik a beágyazott gyermekek számára. Ennek eredményeként meg kell győződnie arról, hogy egyetlen más példány sem hivatkozik az eltávolítottakra (különben újra fennmaradnak).

6. Törlés JPQL utasítás használatával

A hibernálás támogatja a DML-stílusú törlési műveleteket:

Foo foo = új Foo ("foo"); entityManager.persist (foo); flushAndClear (); entitásManager.createQuery ("törlés a Foo-ból, ahol id =: id") .setParameter ("id", foo.getId ()) .executeUpdate (); assertThat (entitásManager.find (Foo.osztály, foo.getId ()), nullValue ());

Fontos megjegyezni, hogy A DML stílusú JPQL utasítások nem befolyásolják az entitáspéldányok állapotát és életciklusát sem, amelyek már be vannak töltve a perzisztencia-kontextusba, ezért javasoljuk, hogy az érintett entitások betöltése előtt hajtsák végre őket.

7. Törlés natív lekérdezések segítségével

Néha vissza kell térnünk a natív lekérdezésekhez, hogy elérjünk valamit, amelyet a Hibernate nem támogat, vagy egy adatbázis-gyártóra jellemző. Törölhetünk adatokat az adatbázisból natív lekérdezésekkel is:

Foo foo = új Foo ("foo"); entityManager.persist (foo); flushAndClear (); entitásManager.createNativeQuery ("törlés a FOO-ból, ahol ID =: id") .setParameter ("id", foo.getId ()) .executeUpdate (); assertThat (entitásManager.find (Foo.osztály, foo.getId ()), nullValue ());

Ugyanaz az ajánlás vonatkozik a natív lekérdezésekre, mint a JPA DML stílusú utasításokra, azaz a natív lekérdezések sem az entitáspéldányok állapotát, sem életciklusát nem befolyásolják, amelyek a lekérdezések végrehajtása előtt a perzisztencia-kontextusba töltődnek be..

8. Lágy törlés

Gyakran nem kívánatos adatokat eltávolítani az adatbázisból az auditálás és az előzmények megőrzése miatt. Ilyen helyzetekben alkalmazhatunk egy soft deletes nevű technikát. Alapvetően csak egy sort jelölünk eltávolítottnak, és az adatok lekérésekor kiszűrjük.

A sok redundáns feltétel elkerülése érdekében hol záradékokat minden lekérdezésben, amely a törölhető entitásokat olvassa, a Hibernate biztosítja a @Hol az entitásra elhelyezhető kommentár, amely tartalmaz egy SQL-töredéket, amelyet automatikusan hozzáad az adott entitáshoz generált SQL-lekérdezésekhez.

Ennek bemutatásához hozzáadjuk a @Hol megjegyzés és egy oszlop TÖRÖLT hoz Foo entitás:

@Entity @Where (clause = "DELETED = 0") public class Foo {// egyéb hozzárendelések @Column (name = "DELETED") private Integer törölve = 0; // getters and setters public void setDeleted () {this.deleted = 1; }}

A következő teszt megerősíti, hogy minden a várt módon működik:

Foo foo = új Foo ("foo"); entityManager.persist (foo); flushAndClear (); foo = entitásManager.find (Foo.osztály, foo.getId ()); foo.setDeleted (); flushAndClear (); assertThat (entitásManager.find (Foo.osztály, foo.getId ()), nullValue ());

9. Következtetés

Ebben a cikkben különféle módszereket vizsgáltunk, amelyek segítségével az adatok Hibernate segítségével törölhetők. Elmagyaráztuk az alapvető fogalmakat és néhány bevált gyakorlatot. Bemutattuk azt is, hogy a soft-deletes miként hajtható végre könnyedén a Hibernate funkcióval.

Ennek az Objektumok törlése hibernált oktatóanyagnak a megvalósítása elérhető a Githubon. Ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.