Auditálás a JPA, a Hibernate és a Spring Data JPA segítségével

1. Áttekintés

Az ORM összefüggésében az adatbázis-naplózás a perzisztens entitásokkal kapcsolatos események nyomon követését és naplózását jelenti, vagy egyszerűen az entitásverziót. SQL eseményindítók ihlette események az entitások beszúrási, frissítési és törlési műveletei. Az adatbázis-naplózás előnyei analógak a forrásverzió-vezérlés nyújtotta előnyökkel.

Három megközelítést mutatunk be az auditálás alkalmazásba történő bevezetésére. Először a standard JPA segítségével valósítjuk meg. Ezután két olyan JPA-bővítményt fogunk megvizsgálni, amelyek saját ellenőrzési funkciókat biztosítanak: az egyiket a Hibernate, a másikat a Spring Data biztosítja.

Itt vannak a mintához kapcsolódó entitások, Rúd és Foo, amelyet ebben a példában használunk:

2. Ellenőrzés a JPA-val

A JPA nem tartalmaz kifejezetten naplózási API-t, de a funkció az entitás életciklusának eseményeivel érhető el.

2.1. @PrePersist,@PreUpdate és @PreRove

A JPA-ban Entitás osztályban, egy módszert meg lehet határozni visszahívásként, amelyet egy adott entitás életciklus-eseménye során hívnak meg. Mivel érdekelnek a visszahívások, amelyeket a megfelelő DML műveletek előtt hajtanak végre, vannak ilyenek is @PrePersist, @PreUpdate és @PreRove a céljainkhoz elérhető visszahívási megjegyzések:

@Entity public class Bar {@PrePersist public void onPrePersist () {...} @PreUpdate public void onPreUpdate () {...} @PreRemove public void onPreRemove () {...}}

A belső visszahívási módszereknek mindig érvénytelennek kell lenniük, és nem tartalmazhatnak argumentumokat. Bármilyen név és hozzáférési szint lehet, de nem lehetnek statikusak.

Ne feledje, hogy a @Változat a JPA-ban szereplő annotáció nem kapcsolódik szigorúan témánkhoz - ez inkább az optimista zároláshoz kapcsolódik, mint az ellenőrzési adatokhoz.

2.2. A visszahívási módszerek megvalósítása

Ennek a megközelítésnek azonban jelentős korlátozása van. Amint azt a JPA 2 specifikáció (JSR 317) előírja:

Általában a hordozható alkalmazás életciklus-módszerének nem szabad hivatkoznia EntityManager vagy Lekérdezés műveleteket, hozzáférhet más entitáspéldányokhoz, vagy módosíthatja a kapcsolatokat ugyanabban a tartóssági környezetben. Az életciklus-visszahívási módszer módosíthatja annak az entitásnak a kapcsolat nélküli állapotát, amelyre hivatkoznak.

Ellenőrzési keretrendszer hiányában manuálisan kell fenntartanunk az adatbázis-sémát és a tartománymodellt. Egyszerű felhasználási esetünkben adjunk hozzá két új tulajdonságot az entitáshoz, mivel csak az „entitás kapcsolaton kívüli állapotát” tudjuk kezelni. An művelet tulajdonság tárolja az elvégzett művelet nevét és a időbélyeg tulajdonság a művelet időbélyegére vonatkozik:

@Entity public class Bar {// ... @Column (name = "operation") private String művelet; @ Oszlop (név = "időbélyeg") privát hosszú időbélyeg; // ... // az új tulajdonságok szabványos beállítói és lekérdezői // ... @PrePersist public void onPrePersist () {audit ("INSERT"); } @PreUpdate public void onPreUpdate () {audit ("UPDATE"); } @PreRemove public void onPreRemove () {audit ("DELETE"); } private void audit (String művelet) {setOperation (művelet); setTimestamp ((új dátum ()). getTime ()); }}

Ha ilyen osztályozást kell hozzáadni több osztályhoz, használhatja @EntityListeners központosítani a kódot. Például:

@EntityListeners (AuditListener.class) @Entity public class Bar {...}
public class AuditListener {@PrePersist @PreUpdate @PreRemove private void beforeAnyOperation (Object object) {...}}

3. Hibernálás Envers

Hibernate használatával ki tudnánk használni Elfogók és EventListeners valamint az adatbázis-kiváltók az audit elvégzéséhez. De az ORM keretrendszer az Envers modult kínálja, amely a tartós osztályok auditálását és verzióinak megvalósítását valósítja meg.

3.1. Kezdés az Envers használatával

Az Envers beállításához hozzá kell adnia a hibernált állapotúak JAR az osztályodba:

 org.hibernate hibernate-envers $ {hibernate.version} 

Ezután csak adja hozzá a @ Auditált annotáció akár egy @Entity (az egész szervezet ellenőrzéséhez) vagy konkrét @Oszlops (ha csak bizonyos tulajdonságokat kell ellenőriznie):

@Entity @Audited public class Bar {...}

Vegye figyelembe, hogy Rúd egy a sokhoz viszonya van Foo. Ebben az esetben vagy auditálnunk kell Foo valamint hozzátéve @ Auditált tovább Foo vagy meg @NotAudited a kapcsolat vagyonán Rúd:

@OneToMany (mappedBy = "bar") @NotAudited private set fooSet;

3.2. Naplótáblák létrehozása

Az ellenőrzési táblák létrehozásának számos módja van:

  • készlet hibernate.hbm2ddl.auto nak nek teremt, create-drop vagy frissítés, így az Envers automatikusan létrehozhatja őket
  • használja org.hibernate.tool.EnversSchemaGenerator hogy a teljes adatbázis-sémát programszerűen exportálja
  • használjon Ant feladatot a megfelelő DDL utasítások előállításához
  • használjon egy Maven beépülő modult az adatbázis-séma előállításához a leképezésekből (például Juplo) az Envers séma exportálásához (a Hibernate 4 és újabb verziókkal működik)

Az első utat járjuk be, mivel ez a legegyszerűbb, de vegye figyelembe, hogy a használat hibernate.hbm2ddl.auto nem biztonságos a gyártásban.

A mi esetünkben, bar_AUD és foo_AUD (ha beállította Foo mint @ Auditált is) táblázatokat kell automatikusan létrehozni. Az ellenőrzési táblák az entitás táblázatából az összes ellenőrzött mezőt két mezővel másolják, REVTYPE (az értékek: „0” a hozzáadáshoz, „1” a frissítéshez, „2” az entitás eltávolításához) és FORDULAT.

Ezeken kívül egy extra táblázat REVINFO alapértelmezés szerint generálódik, két fontos mezőt tartalmaz, FORDULAT és REVTSTMP és rögzíti minden revízió időbélyegét. És mint sejteni lehet, bar_AUD.REV és foo_AUD.REV valójában idegen kulcsok REVINFO.REV.

3.3. Az Envers beállítása

Az Envers tulajdonságait ugyanúgy konfigurálhatja, mint bármely más hibernált tulajdonságot.

Változtassuk meg például az audit tábla utótagját (amely alapértelmezés szerint_AUD") nak nek "_AUDIT_LOG“. Így állíthatja be a megfelelő tulajdonság értékét org.hibernate.envers.audit_table_suffix:

Properties hibernateProperties = new Properties (); hibernateProperties.setProperty ("org.hibernate.envers.audit_table_suffix", "_AUDIT_LOG"); sessionFactory.setHibernateProperties (hibernateProperties);

A rendelkezésre álló tulajdonságok teljes listája megtalálható az Envers dokumentációjában.

3.4. Hozzáférés az entitáselőzményekhez

Az előzetes adatok lekérdezéséhez hasonló módon lehet adatokat lekérdezni a Hibernate feltételek API-n keresztül. Az entitás ellenőrzési előzményei a AuditReader interfész, amely nyitottal érhető el EntityManager vagy Ülés a AuditReaderFactory:

AuditReader olvasó = AuditReaderFactory.get (munkamenet);

Envers biztosítja AuditQueryCreator (visszaadta AuditReader.createQuery ()) audit-specifikus lekérdezések létrehozása érdekében. A következő sor az összeset visszaadja Rúd a 2. változatban módosított példányok (ahol bar_AUDIT_LOG.REV = 2):

AuditQuery lekérdezés = reader.createQuery () .forEntitiesAtRevision (Bar.class, 2)

Így lehet lekérdezni RúdÁtdolgozásai, vagyis az összes listájának megszerzését eredményezi Rúd minden államban ellenőrzött példányok:

AuditQuery lekérdezés = reader.createQuery () .forRevisionsOfEntity (Bar.class, true, true);

Ha a második paraméter hamis, az eredményt összekapcsoljuk a REVINFO táblázat, ellenkező esetben csak az entitáspéldányok kerülnek visszaadásra. Az utolsó paraméter megadja, hogy vissza kell-e adni a töröltet Rúd példányok.

Ezután megadhatja a korlátozásokat a AuditEntity gyári osztály:

query.addOrder (AuditEntity.revisionNumber (). desc ());

4. Spring Data JPA

A Spring Data JPA egy olyan keretrendszer, amely kiterjeszti a JPA-t egy extra absztrakciós réteg hozzáadásával a JPA-szolgáltató tetejére. Ez a réteg támogatást nyújt a JPA-adattárak létrehozásához a Spring JPA-tárház interfészeinek kiterjesztésével.

Céljainkra kiterjesztheti CrudRepository, az interfész az általános CRUD műveletekhez. Amint létrehozta és egy másik összetevőbe fecskendezte a lerakatot, a Spring Data automatikusan biztosítja a megvalósítást, és készen áll az ellenőrzési funkciók hozzáadására.

4.1. A JPA auditálás engedélyezése

Először is szeretnénk engedélyezni az auditálást az annotáció konfigurációján keresztül. Ehhez csak hozzá kell tenni @EnableJpaAuditing tiéden @ Konfiguráció osztály:

@Configuration @EnableTransactionManagement @EnableJpaRepositories @EnableJpaAuditing public class PersistenceConfig {...}

4.2. Spring's Entity Callback Listener hozzáadása

Mint már tudjuk, a JPA biztosítja a @EntityListeners annotáció a visszahívás-figyelő osztályok megadásához. A Spring Data biztosítja a saját JPA entitásfigyelő osztályát: AuditingEntityListener. Tehát adjuk meg a hallgatót a Rúd entitás:

@Entity @EntityListeners (AuditingEntityListener.class) nyilvános osztály bár {...}

A naplózási információkat a hallgató rögzíti a rendszer fenntartásával és frissítésével Rúd entitás.

4.3. A létrehozott és utoljára módosított dátumok követése

Ezután hozzáadunk két új tulajdonságot a létrehozott és utoljára módosított dátumok tárolásához Rúd entitás. A tulajdonságokat a @Létrehozás dátuma és @LastModifiedDate a kommentárokat ennek megfelelően, és értékeik automatikusan beállíthatók:

@Entity @EntityListeners (AuditingEntityListener.class) public class Bar {// ... @Column (name = "created_date", nullable = false, updatable = false) @CreatedDate private long createdDate; @ Oszlop (név = "módosított_dátum") @ UtolsóModifikáltDátum privát hosszú módosítottDátum; // ...}

Általában a tulajdonságokat áthelyezné egy alaposztályba (a @MappedSuperClass), amelyet az összes ellenőrzött entitás kiterjesztene. Példánkban közvetlenül hozzáadjuk őket Rúd az egyszerűség kedvéért.

4.4. A tavaszi biztonsággal kapcsolatos változások szerzőjének ellenőrzése

Ha alkalmazásod a Spring Security programot használja, akkor nemcsak nyomon követheti a módosítások idejét, hanem azt is, hogy ki hajtotta végre őket:

@Entity @EntityListeners (AuditingEntityListener.class) public class Bar {// ... @Column (name = "created_by") @CreatedBy private String createdBy; @ Oszlop (név = "módosított_szerint") @LastModifiedBy privát karakterlánc módosítottBy; // ...}

Az oszlopok a következővel voltak jelölve: @Készítette és @LastModifiedBy az entitást létrehozó vagy utoljára módosító fő nevével vannak feltöltve. Az információkat innen kapják SecurityContext’S Hitelesítés példa. Ha testreszabni kívánja a kommentált mezőkre beállított értékeket, megvalósíthatja AuditorAware felület:

public class AuditorAwareImpl megvalósítja az AuditorAware {@Orride public String getCurrentAuditor () {// az egyéni logikád}}

Az alkalmazás használatának konfigurálása érdekében AuditorAwareImpl hogy megkeresse a jelenlegi igazgatót, nyilvánítson egy babot AuditorAware típusú példány inicializálva van AuditorAwareImpl és adja meg a bab nevét auditorAwareRef paraméter értéke @EnableJpaAuditing:

@EnableJpaAuditing (auditorAwareRef = "auditorProvider") nyilvános osztály PersistenceConfig {// ... @Bean AuditorAware auditorProvider () {return new AuditorAwareImpl (); } // ...}

5. Következtetés

Három megközelítést fontolgattunk az ellenőrzési funkcionalitás megvalósításához:

  • A tiszta JPA megközelítés a legalapvetőbb, és az életciklus-visszahívások használatából áll. Azonban csak egy entitás kapcsolat nélküli állapotát módosíthatja. Ez teszi a @PreRove a visszahívás haszontalan a mi céljainkra, mivel a metódusban elvégzett minden beállítás törlődik, majd az entitással együtt.
  • Az Envers egy kiforrott naplózási modul, amelyet a Hibernate biztosít. Rendkívül konfigurálható és hiányzik a tiszta JPA megvalósítás hibái. Így lehetővé teszi számunkra a törlési művelet ellenőrzését, mivel az entitás táblájától eltérő táblákba jelentkezik be.
  • A Spring Data JPA megközelítés kivonatolja a JPA visszahívásaival való munkát, és praktikus kommentárokat nyújt a tulajdonságok auditálásához. Ez készen áll a Spring Security integrációjára is. Hátránya, hogy ugyanazokat a hibákat örökölte, mint a JPA megközelítése, így a törlési művelet nem ellenőrizhető.

A cikk példái a GitHub-tárházban érhetők el.