Jan Pacek
8.8.2014

Žurnálování Hibernate entit pomocí DB triggerů



V dřívějším příspěvku DB žurnál pomocí Hibernate interceptorů jsem nastínil možnost žurnálování pomocí hibernate interceptorů. Další a asi nejjednodušší možností je použití Hibernate envers, které jsou od hibernate verze 3.5 jeho součástí, které ve své implementaci využívají interceptory a lze je kombinovat dohromady (tzn. pomocí interceptorů řešit to, co envers nenabízí) 

Ale jak tomu na reálných projektech bývá, člověk narazí na omezení ORM a to zejména v oblasti výkonu. Na projektu trading aplikace pro jednu nadnárodní burzovní společnost hraje každá milisekunda roli, a proto žurnálování z aplikačního serveru  není úplně ideální. Žurnálování pomocí envers či interceptorů vyžaduje další provolání do databáze a to přináší určitou režii v distribuovaném systému a větší response time. Cílem tedy bylo použití žurnálování na úrovni databázových triggerů, které jsou generovány přímo z metamodelu Hibernate, aby se uživatel (vývojář, admin) nemusel starat o jejich aktuálnost (tzn. nejlépe aby se mu databáze automaticky aktualizovala) Pro definování auditovaných entit triggery jsem vytvořil Class anotaci, která definovala audit entitu a další parametry pro generované triggery.

@Entity @TriggerAudited(auditEntityClass="com.aspectworks.domain.MyEntityHistory") public class MyEntity extends AbstractEntity{ ... } 

Audit entita (Historizační tabulka) měla (v jednoduchém případě) složený klíč z identifikátoru původní entity (id) a z timestamp property a dědila (pouze v Javě, nikoliv v rámci DB) od původní entity. Mapování pro audit entit sloužilo pro následné čtení historie v aplikaci , ale zejména pro generování auditovacího triggeru.

@Entity public class MyEntityHistory extends MyEntity {
  @Column(name = "LAST_UPDATE_TIME") private Date lastUpdateTime;
}

Generování se provádělo pomocí Hibernate tools – hbmtemplate (v rámci maven  pluginu). Pro generování DDL na triggery jsem vytvořil vlastní TriggerExporter implementaci (poděděnou z org.hibernate.tool.hbm2x.AbstractExporter) s použitím Free Marker Templates. Samotné generování triggerů v této implementaci exporteru načítalo definice z hibernate metamodelu a pro anotované auditované entity vygenerovalo triggery pomocí vytvořené FTL templaty.

while (classIterator.hasNext()) {
  PersistentClass persistentClass = classIterator.next();
  if (persistentClass.getMappedClass().isAnnotationPresent(TriggerAudited.class)) {
    TriggerAudited triggerAudited = (TriggerAudited) persistentClass.getMappedClass().getAnnotation(TriggerAudited.class);
    //Generate trigger ddl via freemarker template for persistent class and target historyClass
    PersistentClass historyClass = getConfiguration().getClassMapping(triggerAudited.auditEntityClass().getName());
  }
}

 Konfigurace v Mavenu  pro spouštění  generování pomocí hibernate3 maven pluginu by vypadala  pak následovně:

<plugin>
  <!-- run "mvn hibernate3:hbmtemplate" to generate a triggers for database auditing -->
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>hibernate3-maven-plugin</artifactId>
  <version>3.0</version>
  <configuration>
    <hibernatetool>
      <configuration configurationfile="${project.basedir}/src/main/resources/hibernate.cfg.xml" />
      <hbmtemplate exporterclass="com.aspectworks.server.persistence.AuditTriggerExporter"/>
    </hibernatetool>
  </configuration>
</plugin>

 Vygenerované DDL skripty pak stačí jen zintegrovat s databází ať již při startu aplikace či v rámci mavenu. Daný příklad s hbmtemplate a FTL šablonami lze samozřejmě využít i na cokoliv jiného, než jen na triggery pro auditování. Zdrojové kódy pro odzkoušení i výsledek výstupu je ke stažení zde.

Vaše emailová adresa nebude zveřejněna

Komentáře

Děkujeme za váš komentář
Další
  • O

    Nedovedu si predstavit pouzit hybernate pro veci, kde se hraje o milisekundy