Hibernate Envers Example
In many business applications, it is of utmost important to track the audit log, when and who has done the changes to the data. There are multiple approaches to achieve it. Hibernate Envers is one of the ways to achieve it. In this article, we will study the Hibernate Envers.
Envers are part of the Hibernate Core module. They aim to provide an easy way to auditing/ versioning the entity class. Envers provide an easy way to create and retrieve the audit logs.
1. Introduction
Envers can support both Hibernate and JPA. In fact, they can be used anywhere the hibernate works like Spring, WildFly, Grails ..etc. Some of the features offered by Envers are as follows,
- Auditing of mapping definitions
- Logging entity revisions
- Querying of historical data
- Support both JPA and Hibernate
- Logging of custom mapping that extends JPA
2. Setup Hibernate Envers
Envers can easily set up and they have annotation support to keep developers’ work minimal. Below are the necessary steps to make Envers work,
- Add
hibernate-envers
dependency in your project - Annotate the target entity classes with
@Audited
- Each of the entity should have an immutable primary key
3. Example
In this section, we will see how to enable auditing for our entity class.
Add hibernate-envers
dependency to the pom.xml
In the entity, class add @Audited
annotation
This annotation instructs hibernate to audit changes to this entity (Create, Update or Delete). From this point, hibernate will create new revision entry for each of the transaction on the annotated entity.
In the example program, I am going to
- Create 2 employees
- List employees
- Update already created employees
- Display audit logs
As shown earlier, auditing is enabled for the entity class. Hibernate creates auditing tables employee_aud
and revinfo
tables for us. When the main program is run below output (covers create, list and update employee record) can be seen in the console as I have enabled the hibernate logging,
At the end of the program created entities are updated. The contents of the employee
table are the following,
Hibernate envers automatically creates logging entries in employee_aud
and revinfo
tables. Contents are as follows,
Audit Table: An audit table is created for each of the entities marked with @Audited annotation. Each audit table contains a primary key from the original entity, all the audited columns, revision type, and revision number.
Revinfo Table: This table maintains the revisions of the entity. It has an integer column revision number and timestamp as a bigint. By default hibernate persists only these two columns. However, it is possible to capture/save additional information as well.
3.1 Retrieving the audit record
In this section, I am going to show how can we retrieve the audit records created by the Hibernate Envers framework.
2 most probable use cases to view audit records are as follows,
- Get all the revisions of an entity
- Get the active revision of an entity at a given point in time
In the example program, I am going to show how to fetch all the revisions of an Employee
entity.
HibernateRetrieveAuditRecordsDemo
public class HibernateRetrieveAuditRecordsDemo { public static void main(String[] args) { SessionFactory sessionfactory = HibernateUtil.getSessionFactory(); Session session = sessionfactory.openSession(); HibernateCreateAuditRecordsDemo.createEmployees(sessionfactory); HibernateCreateAuditRecordsDemo.updateEmployees(sessionfactory); System.out.println("################## Retrieving audit records ####################"); AuditReader reader = AuditReaderFactory.get(session); AuditQuery q = reader.createQuery().forRevisionsOfEntity(Employee.class, false, true); q.add(AuditEntity.property("firstName").like("Santosh", MatchMode.ANYWHERE)); List revisions = q.getResultList(); System.out.println("Number of revisions fetched === " + revisions.size()); revisions.forEach(objects -> { Employee empRecord = (Employee)objects[0]; DefaultRevisionEntity revEntity = (DefaultRevisionEntity)objects[1]; RevisionType revType = (RevisionType)objects[2]; System.out.println(String.format("Employee ID:%d at revision %d with first name %s", empRecord.getId(), revEntity.getId(), empRecord.getFirstName())); }); } }
The output of the above program is as below,
The AuditQuery
interface has many more capabilities to play with hibernate envers audit entities. As an exercise, you can add additional criteria to fetch the history at a given point in time.
4. Download the Source Code
In this section, I am providing a link to the example code.
What do you need to run the program?
- Project is done using Java 11 and IntelliJ Idea IDE
- Import the project using maven
- Program uses PostgresSQL database
- The program
HibernateCreateAuditRecordsDemo
demonstrates how audit entities are created - The program
HibernateRetrieveAuditRecordsDemo
demonstrates how audit entities can be retrieved
You can download the full source code of this example here: Hibernate Enver Example
can we use Hibernate envers for redis(using as persistance storage) ??