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.