Der Standardbenutzer arbeitet in erster Linie mit den aktuellen Daten. Für ihn ist es daher wichtig, dass durch die Historisierung die Performance nicht merklich sinkt. Für einen Applikationsentwickler sollte die Historisierung der Daten möglichst transparent erfolgen. Er möchte sich nicht explizit darum kümmern müssen, er erwartet, dass das verwendete Framework diese Aufgabe automatisch erledigt. Dieser Artikel zeigt, wie diese Anforderungen mit Envers umgesetzt werden können.
Die Entstehung von Envers
Das Projekt Envers (Entity Versioning) wurde von Adam Warski im Jahr 2008 ins Leben gerufen. In seinen Anfängen – namentlich als Preview-Versionen – war Envers befähigt, einfache Properties wie Strings, Numbers und Dates zu versionieren. Später wurde dann das Audit von 1:1- und 1:n-Relationen unterstützt.
Ab dem Envers-1.0.0Beta1-Release konnten Queries auf den historisierten Daten ausgeführt werden. Es war damit möglich, den Zustand einer Entität auf Grund einer Revisionsnummer abzufragen oder die Zustandsentwicklung einer Entität über ihre gesamte Lebensdauer zu verfolgen. Die Envers 1.0.0GA-Version wurde im Juli 2008 veröffentlicht. Sie stellte eine stabile Version der bis dahin entwickelten Features zusammen. Version 1.1.0GA erschien im Oktober 2008. Nebst Codeverbesserungen und Bugfixes lag der Fokus dieses Release in der Unterstützung von persistenten Collections. Mit den steten Verbesserungen im Laufe der Zeit und der zunehmenden Akzeptanz war es nicht weiter verwunderlich, dass Envers Ende Oktober 2008 ein offizielles Hibernate-Modul wurde. Im Frühjahr 2009 erschien die Version 1.2.0GA. Diese enthält in erster Linie die Änderungen, die den Wechsel zu einem offiziellen Hibernate-Modul nötig machten. Die erste offizielle Hibernate-Core-Version, die das Envers-Modul integriert hat, wird Version 3.4.0 GA sein.
Was ist Envers?
Envers ist eine Zusatzbibliothek zu Hibernate, die sich um das Auditieren der Daten kümmert. Das bemerkenswerte an Envers ist, dass es das Auditieren praktisch völlig transparent geschehen lässt. So können Daten, wie mit Hibernate üblich, gelesen und mutiert werden. Ebenso muss das bestehende Datenbankschema nicht verändert, sondern nur durch zusätzliche Tabellen ergänzt werden. Wie im Folgenden gezeigt wird, sind auch die notwendigen Anpassungen im Code nur minimal.
Funktionsweise
Soll eine persistente Klasse (eine mit @Entity annotierte Klasse) auditiert werden, so muss diese zusätzlich mit der Annotation @Audited versehen werden (Listing 1).
@Entity@Auditedpublic class Person {@Id@GeneratedValueprivate int id;private String name;...}
Zur Laufzeit wird dann für jede dieser Klassen eine entsprechende Audit-Entität erstellt. Diese dient als Container für die historisierten Daten. Die gleiche Abbildung findet auch auf der Datenbank statt. Zum Beispiel wird für eine Tabelle PERSON eine entsprechende PERSON_AUD-Tabelle erstellt. In der Datenbank sind somit die aktuellen Daten komplett von den historisierten Daten getrennt (Listing 2).
create table Person (id integer not null,name varchar(255),surname varchar(255),C_VERSION_NUM bigint,primary key (id));create table Person_AUD (id integer not null,REV integer not null,REVTYPE tinyint,name varchar(255),surname varchar(255),primary key (id, REV));
Ähnlich wie bei Subversion werden alle in einer Transaktion durchgeführten Änderungen mit der gleichen globalen Revisionsnummer versehen. Jede Revision definiert also einen konsistenten Zustand der Daten.




