Auditovanie pomocou JPA, Hibernate a Spring Data JPA

1. Prehľad

V kontexte ORM znamená auditovanie databázy sledovanie a zaznamenávanie udalostí súvisiacich s perzistentnými entitami alebo jednoducho s verziou entít. Inšpirované spúšťačmi SQL sú udalosťami operácie vkladania, aktualizácie a mazania entít. Výhody auditu databázy sú analogické s tými, ktoré poskytuje kontrola zdrojovej verzie.

Predvedieme tri prístupy k zavedeniu auditu do aplikácie. Najskôr ho implementujeme pomocou štandardného JPA. Ďalej sa pozrieme na dve rozšírenia JPA, ktoré poskytujú svoje vlastné kontrolné funkcie: jednu poskytuje Hibernate a druhú Spring Data.

Tu sú vzorky súvisiacich subjektov, Bar a Foo, ktoré sa použijú v tomto príklade:

2. Auditovanie pomocou JPA

JPA výslovne neobsahuje auditovacie API, ale funkčnosť je možné dosiahnuť pomocou udalostí životného cyklu entity.

2.1. @PrePersist,@PreUpdate a @PreRemove

V JPA Subjekt triedy, metódu je možné určiť ako spätné volanie, ktoré sa vyvolá počas konkrétnej udalosti životného cyklu entity. Pretože nás zaujímajú spätné volania, ktoré sa vykonávajú pred zodpovedajúcimi operáciami DML, existujú @PrePersist, @PreUpdate a @PreRemove anotácie spätného volania dostupné pre naše účely:

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

Interné metódy spätného volania by mali vždy vrátiť void a nemali by brať žiadne argumenty. Môžu mať akýkoľvek názov a ľubovoľnú úroveň prístupu, nemali by však byť statické.

Uvedomte si, že @ Verzia anotácia v JPA nesúvisí striktne s našou témou - týka sa viac optimistického zamykania ako údajov auditu.

2.2. Implementácia metód spätného volania

Tento prístup však predstavuje značné obmedzenie. Ako je uvedené v špecifikácii JPA 2 (JSR 317):

Metóda životného cyklu prenosnej aplikácie by sa vo všeobecnosti nemala dovolávať EntityManager alebo Dopyt operácie, prístup k ďalším inštančným entitám alebo úprava vzťahov v rovnakom kontexte perzistencie. Metóda spätného volania životného cyklu môže zmeniť stav nepríbuznosti entity, na ktorú je vyvolaná.

Ak neexistuje rámec pre audit, musíme databázovú schému a model domény udržiavať manuálne. Pre náš jednoduchý prípad použitia pridajme k entite dve nové vlastnosti, pretože môžeme spravovať iba „stav, ktorý nemá vzťah k entite“. An prevádzka vlastnosť uloží názov vykonanej operácie a a časová značka vlastnosť je pre časovú pečiatku operácie:

@Entity verejná trieda Bar {// ... @Column (name = "operation") súkromná reťazcová operácia; @Column (name = "timestamp") súkromná dlhá časová pečiatka; // ... // štandardní zadávatelia a obstarávatelia nových vlastností // ... @PrePersist public void onPrePersist () {audit ("INSERT"); } @PreUpdate public void onPreUpdate () {audit ("UPDATE"); } @PreRemove public void onPreRemove () {audit ("ODSTRÁNIŤ"); } audit súkromných prázdnin (operácia reťazca) {setOperation (operácia); setTimestamp ((new Date ()). getTime ()); }}

Ak potrebujete pridať takýto audit do viacerých tried, môžete použiť @EntityListeners centralizovať kód. Napríklad:

@EntityListeners (AuditListener.class) @Entity verejný bar triedy {...}
verejná trieda AuditListener {@PrePersist @PreUpdate @PreRemove súkromné ​​void beforeAnyOperation (objekt objektu) {...}}

3. Hibernácia Envers

S Hibernate by sme mohli využiť Interceptory a Poslucháči udalostí ako aj spúšťače databázy na vykonanie auditu. Rámec ORM ale ponúka Envers, modul implementujúci auditovanie a verzovanie perzistentných tried.

3.1. Začnite s programom Envers

Ak chcete nastaviť program Envers, musíte pridať prezimovať JAR do tvojej triedy:

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

Potom už len pridajte @Auditované anotácia buď na @Entity (vykonať audit celého subjektu) alebo na konkrétnom @ Stĺpecs (ak potrebujete skontrolovať iba konkrétne vlastnosti):

@Entity @Audited verejná trieda Bar {...}

Poznač si to Bar má vzťah typu one-to-many Foo. V takom prípade musíme vykonať audit Foo aj pridaním @Auditované na Foo alebo nastaviť @NotAudited o majetku vzťahu v Bar:

@OneToMany (mappedBy = "bar") @NotAudited súkromná sada fooSet;

3.2. Vytváranie tabuliek protokolu auditu

Existuje niekoľko spôsobov, ako vytvoriť tabuľky auditu:

  • nastaviť prezimovat.hbm2ddl.auto do vytvoriť, create-drop alebo aktualizovať, takže program Envers ich môže vytvárať automaticky
  • použite org.hibernate.tool.EnversSchemaGenerator programovo exportovať celú databázovú schému
  • použite úlohu Ant na vygenerovanie vhodných príkazov DDL
  • použite doplnok Maven na generovanie databázovej schémy z vašich mapovaní (napríklad Juplo) na export schémy Envers (funguje s režimom Hibernate 4 a vyšším)

Pôjdeme prvou cestou, pretože je najpriamočiarejšia, ale uvedomte si, že pomocou prezimovat.hbm2ddl.auto nie je bezpečný pri výrobe.

V našom prípade bar_AUD a foo_AUD (ak ste nastavili Foo ako @Auditované tiež) tabuľky by sa mali generovať automaticky. Tabuľky auditu kopírujú všetky kontrolované polia z tabuľky entity s dvoma poľami, REVTYPE (hodnoty sú: „0“ pre pridanie, „1“ pre aktualizáciu, „2“ pre odstránenie entity) a REV.

Okrem nich pomenovaná ďalšia tabuľka REVINFO bude generované štandardne, obsahuje dve dôležité polia, REV a REVTSTMP a zaznamenáva časovú pečiatku každej revízie. A ako tušíte, bar_AUD.REV a foo_AUD.REV sú vlastne cudzie kľúče k REVINFO.REV.

3.3. Konfigurácia programu Envers

Vlastnosti Envers môžete nakonfigurovať rovnako ako ktorékoľvek iné vlastníctvo dlhodobého spánku.

Napríklad, zmeňme príponu tabuľky auditu (predvolená je „_AUD„) Až“_AUDIT_LOG„. Týmto spôsobom je možné nastaviť hodnotu zodpovedajúcej vlastnosti org.hibernate.envers.audit_table_suffix:

Vlastnosti hibernateProperties = nové Vlastnosti (); hibernateProperties.setProperty ("org.hibernate.envers.audit_table_suffix", "_AUDIT_LOG"); sessionFactory.setHibernateProperties (hibernateProperties);

Celý zoznam dostupných vlastností nájdete v dokumentácii Envers.

3.4. Prístup k histórii entít

Historické údaje môžete vyhľadávať podobným spôsobom ako pri dotazovaní údajov prostredníctvom rozhrania API kritérií dlhodobého spánku. K histórii auditu entity je možné pristupovať pomocou AuditReader rozhranie, ktoré je možné získať otvoreným EntityManager alebo Session cez AuditReaderFactory:

Čítačka AuditReader = AuditReaderFactory.get (relácia);

Envers poskytuje AuditQueryCreator (vrátil sa AuditReader.createQuery ()), aby ste mohli vytvoriť dotazy špecifické pre audit. Nasledujúci riadok vráti všetky Bar prípady upravené pri revízii # 2 (kde bar_AUDIT_LOG.REV = 2):

AuditQuery query = reader.createQuery () .forEntitiesAtRevision (Bar.class, 2)

Tu je postup, ako zadať dopyt BarBude mať za následok získanie zoznamu všetkých Bar inštancie vo všetkých ich štátoch, ktoré boli podrobené auditu:

AuditQuery query = reader.createQuery () .forRevisionsOfEntity (Bar.class, true, true);

Ak je druhý parameter nepravdivý, výsledok sa spojí s REVINFO tabuľka, inak sa vrátia iba inštancie entít. Posledný parameter určuje, či sa má vrátiť zmazané Bar inštancie.

Potom môžete určiť obmedzenia pomocou AuditEntity továrenská trieda:

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

4. Jarné údaje JPA

Spring Data JPA je rámec, ktorý rozširuje JPA o ďalšiu vrstvu abstrakcie navrch poskytovateľa JPA. Táto vrstva umožňuje podporu vytvárania úložísk JPA rozšírením rozhraní úložiska Spring JPA.

Pre naše účely môžete rozšíriť Úložisko Crud, rozhranie pre všeobecné operácie CRUD. Hneď ako vytvoríte a vložíte svoje úložisko do iného komponentu, Spring Data zabezpečí implementáciu automaticky a ste pripravení pridať funkčnosť auditu.

4.1. Povolenie auditu JPA

Na začiatok chceme povoliť auditovanie pomocou konfigurácie anotácií. Ak to chcete urobiť, stačí pridať @EnableJpaAuditing na tvojom @ Konfigurácia trieda:

@Configuration @EnableTransactionManagement @EnableJpaRepositories @EnableJpaAuditing verejnej triedy PersistenceConfig {...}

4.2. Pridanie poslucháča spätného volania entity Spring

Ako už vieme, JPA poskytuje @EntityListeners anotácia na určenie tried poslucháčov spätného volania. Spring Data poskytuje vlastnú triedu poslucháčov entít JPA: AuditingEntityListener. Poďme teda určiť poslucháča súboru Bar subjekt:

@Entity @EntityListeners (AuditingEntityListener.class) Bar verejnej triedy {...}

Teraz bude poslucháč zachytávať informácie o audite pri pretrvávaní a aktualizácii súboru Bar subjekt.

4.3. Sledovanie vytvorených a naposledy zmenených dátumov

Ďalej do nášho pridáme dve nové vlastnosti na ukladanie vytvorených a naposledy upravených dátumov Bar subjekt. Vlastnosti sú poznámkami @CreatedDate a @LastModifiedDate anotácie a ich hodnoty sa nastavia automaticky:

@Entity @EntityListeners (AuditingEntityListener.class) verejná trieda Bar {// ... @Column (name = "created_date", nullable = false, updatable = false) @CreatedDate private long createdDate; @Column (name = "modified_date") @LastModifiedDate private long modifiedDate; // ...}

Spravidla by ste presunuli vlastnosti do základnej triedy (s poznámkou @MappedSuperClass), ktorú by rozšírili všetky vaše kontrolované subjekty. V našom príklade ich pridávame priamo do Bar kvôli jednoduchosti.

4.4. Audit autora zmien s jarnou bezpečnosťou

Ak vaša aplikácia používa Spring Security, môžete nielen sledovať, kedy boli vykonané zmeny, ale aj to, kto ich vykonal:

@Entity @EntityListeners (AuditingEntityListener.class) verejná trieda Bar {// ... @Column (name = "created_by") @CreatedBy private String createdBy; @Column (name = "modified_by") @LastModifiedBy private String modifiedBy; // ...}

Stĺpce s poznámkami @Vytvoril a @LastModifiedBy sú vyplnené menom príkazcu, ktorý vytvoril alebo naposledy upravil entitu. Informácie sú čerpané z SecurityContext‘S Overenie inštancia. Ak chcete prispôsobiť hodnoty, ktoré sú nastavené na anotované polia, môžete ich implementovať AuditorAware rozhranie:

verejná trieda AuditorAwareImpl implementuje AuditorAware {@Override public String getCurrentAuditor () {// vaša vlastná logika}}

Za účelom konfigurácie aplikácie na použitie AuditorAwareImpl Ak chcete vyhľadať aktuálneho príkazcu, vyhláste fazuľu o AuditorAware typ inicializovaný inštanciou AuditorAwareImpl a zadajte názov fazule ako auditorAwareRef hodnota parametra v @EnableJpaAuditing:

@EnableJpaAuditing (auditorAwareRef = "auditorProvider") verejná trieda PersistenceConfig {// ... @Bean AuditorAware auditorProvider () {return new AuditorAwareImpl (); } // ...}

5. Záver

Zvážili sme tri prístupy k implementácii funkčnosti auditu:

  • Čistý prístup JPA je najzákladnejší a spočíva v použití spätných väzieb životného cyklu. Môžete však upravovať iba stav nepríbuzného vzťahu entity. Toto robí @PreRemove spätné volanie zbytočné pre naše účely, pretože všetky nastavenia, ktoré ste v metóde vykonali, sa potom odstránia spolu s entitou.
  • Envers je vyspelý audítorský modul poskytovaný spoločnosťou Hibernate. Je vysoko konfigurovateľný a chýbajú mu nedostatky čistej implementácie JPA. Umožňuje nám tak auditovať operáciu odstránenia, pretože sa prihlasuje do iných tabuliek, ako je tabuľka entity.
  • Prístup Spring Data JPA abstrakuje prácu s spätnými volaniami JPA a poskytuje užitočné anotácie pre vlastnosti auditu. Je tiež pripravený na integráciu s Spring Security. Nevýhodou je, že zdedí rovnaké chyby v prístupe JPA, takže operáciu mazania nemožno auditovať.

Príklady tohto článku sú k dispozícii v úložisku GitHub.


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