Spring Boot With Hibernate Envers

Hibernate Envers provides an easy & flexible way to implement database auditing and versioning. Database Auditing in the context of JPA means tracking and logging the changes on persisted entities. The database audit logs are important from compliance perspectives and also provides grate helps to identify how and what data has been changed.

Hibernate Envers can be integrated very easyly with Spring Boot JPA.

The code for this post is available on Github here

To use Envers in Spring boot application, We need to add below dependency.

1
2
3
4
5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>5.4.30.Final</version>
</dependency>

To Audit changes that are performed on an entity, we need to add @Audited annotation on the entity.

Considering we have a UserDetails entity,for which we want to enable Auditing.
1
2
3
4
5
6
7
8
@Entity
@Audited
public class UserDetails {
@Id
private Integer userId;
private String firstName;
private String lastName;
}

In order to log all the changes to entity, Envers needs REVINFO and Entity_aud table, In this case it will be USER_DETAILS_AUD.
The REVINFO table contains revision id and revision timestamp. A row is inserted into this table on each new revision, that is, on each commit of a transaction, which changes audited data.

flyway migration scripts for the the audit table and revinfo table will look like below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

CREATE TABLE REVINFO (
REV INTEGER GENERATED BY DEFAULT AS IDENTITY,
REVTSTMP BIGINT,
PRIMARY KEY (REV)
);

CREATE TABLE USER_DETAILS (
USER_ID INTEGER PRIMARY KEY,
FIRST_NAME VARCHAR(50) NOT NULL,
LAST_NAME VARCHAR(50) NOT NULL
);

CREATE TABLE USER_DETAILS_AUD (
USER_ID INTEGER NOT NULL,
FIRST_NAME VARCHAR(50),
LAST_NAME VARCHAR(50),
REV INTEGER NOT NULL,
REVTYPE INTEGER NOT NULL,
PRIMARY KEY (USER_ID, REV)
);

Now when we insert,update and delete UserDetails entity, audit log will be saved in USER_DETAILS_AUD table.

for below code we should expect 4 rows in USER_DETAILS_AUD table
1
2
3
4
5
6
7
8
9
10
11
12
private void dataSetup(UserDetailsRepository userRepository) {
UserDetails userDetails = new UserDetails(1, "NIRAJ", "SONAWANE");
userRepository.save(userDetails); // Create

userDetails.setFirstName("Updated Name");
userRepository.save(userDetails); // Update-1

userDetails.setLastName("Updated Last name"); // Update-2
userRepository.save(userDetails);

userRepository.delete(userDetails); // Delete
}

The REVTYPE column value is taken from the RevisionType Enum. Which has values
0-Add
1-Update
2-Delete

The code for this post is available on Github here

Share Comments