Revizija s JPA, Hibernate i Spring Data JPA

1. Pregled

U kontekstu ORM-a, revizija baze podataka znači praćenje i bilježenje događaja povezanih s trajnim entitetima ili jednostavno verziranje entiteta. Inspirirani SQL okidačima, događaji su operacije umetanja, ažuriranja i brisanja entiteta. Prednosti revizije baze podataka analogne su onima koje pruža kontrola izvornih verzija.

Pokazat ćemo tri pristupa uvođenju revizije u aplikaciju. Prvo ćemo ga implementirati pomoću standardnog JPA. Zatim ćemo razmotriti dva JPA proširenja koja pružaju vlastite funkcionalnosti revizije: jedno pruža Hibernate, drugo Spring Data.

Evo primjera povezanih entiteta, Bar i Foo, koji će se koristiti u ovom primjeru:

2. Revizija sa JPA

JPA ne sadrži eksplicitno API za reviziju, ali funkcionalnost se može postići pomoću događaja životnog ciklusa entiteta.

2.1. @PrePersist,@PreUpdate i @PreRemove

U JPA Entitet klase, metoda se može odrediti kao povratni poziv koji će se pozivati ​​tijekom određenog događaja životnog ciklusa entiteta. Kako nas zanimaju povratni pozivi koji se izvršavaju prije odgovarajućih DML operacija, postoje @PrePersist, @PreUpdate i @PreRemove Bilješke povratnog poziva dostupne u naše svrhe:

Traka javne klase @Entity {@PrePersist public void onPrePersist () {...} @PreUpdate public void onPreUpdate () {...} @PreRemove public void onPreRemove () {...}}

Interne metode povratnog poziva uvijek bi trebale biti void i ne uzimati nikakve argumente. Mogu imati bilo koje ime i bilo koju razinu pristupa, ali ne smiju biti statični.

Budite svjesni da @Verzija napomena u JPA nije striktno povezana s našom temom - to je više povezano s optimističnim zaključavanjem nego s podacima revizije.

2.2. Implementacija metoda povratnog poziva

Ipak, s ovim pristupom postoje značajna ograničenja. Kao što je navedeno u specifikaciji JPA 2 (JSR 317):

Općenito, metoda životnog ciklusa prijenosne aplikacije ne bi se trebala pozivati EntityManager ili Upit operacije, pristup drugim instancama entiteta ili modificiranje odnosa u istom kontekstu postojanosti. Metoda povratnog poziva životnog ciklusa može modificirati stanje nepovezanosti entiteta na koji se poziva.

U nedostatku revizijskog okvira, moramo ručno održavati shemu baze podataka i model domene. Za naš jednostavan slučaj, dodajmo dva nova svojstva entitetu, jer možemo upravljati samo "ne-odnosnim stanjem entiteta". An operacija svojstvo će pohraniti naziv izvršene operacije i a vremenska oznaka svojstvo je za vremensku oznaku operacije:

@ Entity javna traka klase {// ... @Column (name = "operation") private String operacija; @Column (name = "timestamp") privatna duga vremenska oznaka; // ... // standardni postavljači i getteri za nova svojstva // ... @PrePersist public void onPrePersist () {audit ("INSERT"); } @PreUpdate javna praznina onPreUpdate () {audit ("UPDATE"); } @PreRemove public void onPreRemove () {audit ("DELETE"); } revizija privatne praznine (operacija niza) {setOperation (operacija); setTimestamp ((novi datum ()). getTime ()); }}

Ako takvu reviziju trebate dodati u više klasa, možete je koristiti @EntityListeners za centraliziranje koda. Na primjer:

@EntityListeners (AuditListener.class) @ Bar javne klase Entity {...}
javna klasa AuditListener {@PrePersist @PreUpdate @PreRemove private void beforeAnyOperation (objektni objekt) {...}}

3. Hibernate Envers

Hibernate bi mogli iskoristiti Presretači i Slušatelji događaja kao i okidači baze podataka za provođenje revizije. Ali ORM okvir nudi Envers, modul koji provodi reviziju i izradu verzija postojanih klasa.

3.1. Započnite s Enversom

Da biste postavili Envers, morate dodati hibernirati-envers JAR u vašu stazu:

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

Zatim samo dodajte @ Revidirano napomena bilo na @ Entitet (za reviziju cijelog entiteta) ili na određeno @Stupacs (ako trebate revidirati samo određena svojstva):

@Entity @Audited Bar javne klase {...}

Imajte na umu da Bar ima odnos jedan prema mnogima Foo. U ovom slučaju, ili moramo izvršiti reviziju Foo kao i dodavanjem @ Revidirano na Foo ili postaviti @NotAudited na svojstvu veze u Bar:

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

3.2. Izrada tablica dnevnika revizije

Postoji nekoliko načina za stvaranje tablica revizije:

  • postavljen zimski san.hbm2ddl.auto do stvoriti, stvoriti-ispustiti ili ažuriranje, tako da ih Envers može automatski stvoriti
  • upotrijebite org.hibernate.tool.EnversSchemaGenerator za programski izvoz cjelokupne sheme baze podataka
  • upotrijebite zadatak Ant da biste generirali odgovarajuće DDL izjave
  • upotrijebite dodatak Maven za generiranje sheme baze podataka iz vaših mapiranja (kao što je Juplo) za izvoz Enversove sheme (radi s Hibernate 4 i novijim)

Ići ćemo prvom rutom, jer je najjednostavnija, ali imajte na umu da je korištenje zimski san.hbm2ddl.auto nije siguran u proizvodnji.

U našem slučaju, bar_AUD i foo_AUD (ako ste postavili Foo kao @ Revidirano isto tako) tablice treba generirati automatski. Tablice revizije kopiraju sva revidirana polja iz tablice entiteta s dva polja, REVTIP (vrijednosti su: "0" za dodavanje, "1" za ažuriranje, "2" za uklanjanje entiteta) i REV.

Osim ovih, dodatna tablica nazvana REVINFO generirat će se prema zadanim postavkama, uključuje dva važna polja, REV i REVTSTMP i bilježi vremensku oznaku svake revizije. I kao što možete pretpostaviti, bar_AUD.REV i foo_AUD.REV zapravo su strani ključevi za REVINFO.REV.

3.3. Konfiguriranje Envera

Envers svojstva možete konfigurirati baš kao i bilo koje drugo svojstvo hibernacije.

Na primjer, promijenimo sufiks tablice revizije (koji je prema zadanim postavkama postavljen na „_AUD") Do"_AUDIT_LOG“. Evo kako postaviti vrijednost odgovarajućeg svojstva org.hibernate.envers.audit_suffix_table:

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

Cjelovit popis dostupnih svojstava nalazi se u Enversovoj dokumentaciji.

3.4. Pristup povijesti entiteta

Možete tražiti povijesne podatke na način sličan upitu podataka putem API-ja kriterija hibernacije. Povijesti revizije entiteta može se pristupiti pomoću AuditReader sučelje, koje se može dobiti s otvorenim EntityManager ili Sjednica putem AuditReaderFactory:

Čitač AuditReader = AuditReaderFactory.get (sesija);

Envers pruža AuditQueryCreator (vratio AuditReader.createQuery ()) kako bi se stvorili upiti specifični za reviziju. Sljedeći će red vratiti sve Bar slučajevi izmijenjeni u reviziji # 2 (gdje bar_AUDIT_LOG.REV = 2):

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

Evo uputa za upit BarRevizije, tj. Rezultirat će dobivanjem popisa svih Bar slučajevi u svim njihovim državama koje su bile revidirane:

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

Ako je drugi parametar netačan, rezultat se pridružuje znaku REVINFO tablice, u suprotnom, vraćaju se samo instance entiteta. Posljednji parametar određuje hoće li se vratiti izbrisano Bar instance.

Tada možete odrediti ograničenja pomoću AuditEntity tvornička klasa:

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

4. Spring Data JPA

Spring Data JPA je okvir koji proširuje JPA dodavanjem dodatnog sloja apstrakcije na vrh JPA dobavljača. Ovaj sloj omogućuje podršku za stvaranje JPA spremišta širenjem sučelja JPA spremišta Spring.

U naše svrhe možete produžiti CrudRepository, sučelje za generičke CRUD operacije. Čim ste stvorili i ubrizgali svoje spremište u drugu komponentu, Spring Data omogućit će implementaciju automatski i spremni ste za dodavanje funkcionalnosti revizije.

4.1. Omogućavanje JPA revizije

Za početak želimo omogućiti reviziju putem konfiguracije napomena. Da biste to učinili, samo dodajte @EnableJpaAuditing na tvoj @Konfiguracija razred:

@Configuration @EnableTransactionManagement @EnableJpaRepositories @EnableJpaAuditing javna klasa PersistenceConfig {...}

4.2. Dodavanje slušatelja povratnog poziva Spring Entity

Kao što već znamo, JPA nudi @EntityListeners napomena za specificiranje klasa slušatelja povratnog poziva. Spring Data nudi vlastitu klasu slušatelja JPA entiteta: AuditingEntityListener. Pa odredimo slušatelja za Bar entitet:

Traka javne klase @Entity @EntityListeners (AuditingEntityListener.class) {...}

Sada će slušatelji hvatati informacije o reviziji prilikom ustrajavanja i ažuriranja Bar entitet.

4.3. Praćenje izrađenih i posljednjih izmjena datuma

Dalje, u naša ćemo dodati dva nova svojstva za pohranu stvorenih i zadnji put izmijenjenih datuma Bar entitet. Svojstva su označena znakom @CreatedDate i @LastModifiedDate napomene u skladu s tim, a njihove se vrijednosti postavljaju automatski:

@Entity @EntityListeners (AuditingEntityListener.class) traka javne klase {// ... @Column (name = "created_date", nullable = false, Updatable = false) @CreatedDate private long createdDate; @Column (name = "modified_date") @LastModifiedDate private long modifiedDate; // ...}

Općenito, svojstva biste premjestili u osnovnu klasu (označen s @MappedSuperClass) koju bi proširili svi vaši subjekti kod kojih je izvršena revizija. U našem primjeru dodajemo ih izravno u Bar Zbog jednostavnosti.

4.4. Revizija autora promjena s proljetnom sigurnošću

Ako vaša aplikacija koristi Spring Security, ne samo da možete pratiti kada su izvršene promjene, već i tko ih je izvršio:

@Entity @EntityListeners (AuditingEntityListener.class) traka javne klase {// ... @Column (name = "created_by") @CreatedBy private String createdBy; @Column (name = "modified_by") @LastModifiedBy private String modifiedBy; // ...}

Stupci označeni s @Napravio i @LastModifiedBy se popunjavaju imenom principala koji je stvorio ili posljednju izmjenu entiteta. Informacije su izvučene iz SecurityContext‘S Ovjera primjer. Ako želite prilagoditi vrijednosti koje su postavljene na označena polja, možete ih implementirati AuditorAware sučelje:

javna klasa AuditorAwareImpl implementira AuditorAware {@Override public String getCurrentAuditor () {// vaša prilagođena logika}}

Da biste konfigurirali aplikaciju za upotrebu AuditorAwareImpl potražiti trenutnu glavnicu, proglasiti grah od AuditorAware tip inicijaliziran instancom od AuditorAwareImpl i navedite ime graha kao auditorAwareRef vrijednost parametra u @EnableJpaAuditing:

@EnableJpaAuditing (auditorAwareRef = "auditorProvider") javna klasa PersistenceConfig {// ... @Bean AuditorAware auditorProvider () {return new AuditorAwareImpl (); } // ...}

5. Zaključak

Razmotrili smo tri pristupa primjeni funkcionalnosti revizije:

  • Čisti JPA pristup najosnovniji je i sastoji se od korištenja povratnih poziva u životnom ciklusu. Međutim, smijete mijenjati samo stanje odnosa entiteta. To čini @PreRemove povratni poziv beskoristan u naše svrhe, jer će se sve postavke koje ste izvršili u metodi izbrisati zajedno s entitetom.
  • Envers je modul za zrelu reviziju koji pruža Hibernate. Vrlo je konfigurabilan i nedostaju mu nedostaci čistog provođenja JPA. Dakle, omogućuje nam reviziju operacije brisanja, jer se prijavljuje u tablice koje nisu tablice entiteta.
  • JPA pristup Spring Data apstrahira rad s povratnim pozivima JPA i pruža korisne napomene za reviziju svojstava. Također je spreman za integraciju s Spring Security. Nedostatak je što nasljeđuje iste nedostatke JPA pristupa, pa se operacija brisanja ne može revidirati.

Primjeri za ovaj članak dostupni su u spremištu GitHub.


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