Database Transaction Auditing using Spring Envers

Technology:

Spring Data is one module built on top of the spring framework for easy database transactions. It provides various interfaces, and annotation for easy outsource Java development. Spring data make use of @Repository annotation, one of stereotype of the annotation provided by Spring framework for creating database access related beans.

database-transaction

We need to enable the spring data using @EnableJpaRepositories annotation.

If we are using XML based namespaces, then we can use below configuration:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <jpa:repositories base-package="com.example.repositories"/> </beans>

Alternatively, Spring data also provides @RepositoryDefinition annotation if we are not implementing the spring data interfaces.

In some cases, we used to write base interfaces across the application, for these interfaces, we won’t want to create spring beans for it, Spring data provides @NoRepositoryBean annotation for the same thing to exclude classes to create beans.

Database Auditing without using Spring framework Envers:

The JPA providersdoes not explicitly provide auditing, but we can achieve the auditing using lifecycle events.

JPA will provides @PrePersist, @PreUpdate and @PreRemove annotation for before transaction commits, and @PostPersist, @PostUpdate, @PostRemove annotations for after transaction commits.

We can use these annotations either at entity level, or we can write these annotated methods in a separate class and we can provide at class level as entity listener.

public class AuditListener { @PrePersist private void beforeInsert(Object object) { ... } @PreUpdate private void beforeUpdate(Object object) { ... } @PreRemove private void beforeDelete(Object object) { ... } @PostPersist private void AfterInsert(Object object) { ... } @PostUpdate private void AfterUpdate(Object object) { ... } @PostRemove private void AfterDelete(Object object) { ... } } And Entity class will look like below: @EntityListeners(AuditListener.class) @Entity public class SampleEntity { // methods }

If we want to query for entity revision using JPA, we need to create audited entities also, need to implement all CRUD operation for it.

Database Auditing using Spring framework Envers:

If we use Spring Data JPA, it will provide an event listener for all operations, also it introduces one Repository implementation RevisionRepository interface for querying the Audited data.

Dependencies:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-envers</artifactId> </dependency>

The above dependencies are required if we are using spring boot, if not we need to check for the compactible version for both libraries.

Enabling JPA Auditing in Spring Data JPA:

Spring Data Envers provides @EnableJpaAuditing annotation for bootstrapping Envers related beans, and AuditingEntityListener is the abstract listener for all our common auditing features.

Add this listener at class level, for those entities we want to enable the auditing, similar JPA implementation but listener class will be provided by Spring Data Envers.

@EntityListeners(AuditingEntityListener.class) @Entity public class SampleEntity { // methods }

For Spring Data Repository interface implement the RevisionRepository interface for revision fetching.

Adding user principal information in Entity Audits:

If we are using Spring security, we can also track the changes made by user, using AuditAware interface.

For tracking the user changes need to annotate 2 of entity fields with @LastModifiedBy,@CreatedBy to track the changes.

And the values for these fields will be set by AuditAware interface implementation.

We need to create one bean of the AuditAware which is the implementation of this interface and provide the bean reference to @EnableJpaAuditing annotation as an argument.

class SpringSecurityAuditorAware implements AuditorAware<UserDetails> { publicUserDetailsgetCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { return null; } return ((UserDetails) authentication.getPrincipal()).getUser(); } } @Configuration @EnableJpaAuditing(auditorAwareRef="auditorProvider ") public class AuditConfig { @Bean AuditorAware<String>auditorProvider() { return new SpringSecurityAuditorAware(); } }

Tracking Creation Dates and Modification Dates:

Similar to @LastModifiedBy,@CreatedBy annotation, we have @CreatedDate, @LastModifiedDate annotations for tracking creation and modified dates.

As a best practice, move all these common fields to base entity class and every Entity class must extended this base entity class and it needs to be annotated with @MappedSuperClass annotation.

Conclusion:

JPA specification will not directly provide a way for auditing, but we can achieve through the event listeners, and we need to write a lot of code at each entity level to achieve it.

Spring Data Envers is one of the library which will eliminates majority of repeated code by using annotations. Spring Data Envers provides RevisionRepository interface for queryin audit history of the entity, and also if we are using Spring security in our application, we can also track the changes done by a particular user using AuditorAware interface.