Introduction
Database auditing in the context of ORM refers to the monitoring and logging of persistent entity-related events, or just entity versioning. These events are insert, update, and delete operations on entities and are modeled after SQL triggers. The advantages of database auditing are comparable to those of source version control.
Getting Started
Here, I'm using Spring JPA provided features as well as some Hibernate features in order to perform this task. Basically, our main idea is to create a JPA EntityManagerFactory and let it handle all the low level tasks to manage related to auditing.
So, firstly let's have a quick look on how to create a JPA EntityManagerFactory.
- Firstly you may've to create a Configuration Class (@Configuration) called "EntityManagerDatasourceConfig.java".
- Then we've to define which are the relevent JPA repositories which are going to handled through this EntityManagerFactory with @EnableJpaRepositories(basePackages = "com.devsdebugger.audit.repository") annotation by mentioning your repository package names.
- Then defined a bean method with @Bean(name = "entityManagerFactory") annotation to define bean with the name of "entityManagerFactory".
- Then we've to create an instance of LocalContainerEntityManagerFactoryBean which we need to create EntityManagerFactory object.
- Then we've set new instance of HibernatePersistenceProvider as the setPersistenceProvider() method of EntityManager object.
- Then we've to set our entity package for the setPackagesToScan() method of EntityManager object.
- Then we've to set our javax.sql.DataSource instance we've autowired at the beginning of the class for the setDataSource() method of EntityManager object.
- Then we're ready to set the properties by initialising new Properties() object.
- As the first property, I've set property method setProperty("org.hibernate.envers.audit_table_suffix", "_hst") to override the audit table default audit suffix of "_AUD" to "_hst".
- As per the second property, I've set property method properties.setProperty("hibernate.hbm2ddl.auto", "update"); to update table structure for development purposes which is not a mandatory property but would be useful in an emergency changes occurs in the DB to regenerate the table structure.
- Finally we need to set all those defined properties to EntityManagerFactory object to do the needful by using setJpaProperties(properties) method of EntityManager object.
Below mentioned piece of code indicates the final outcome of the EntityManagerFactory.
import lombok.RequiredArgsConstructor;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
@RequiredArgsConstructor
@Configuration
@EnableJpaRepositories(basePackages = "com.devsdebugger.audit.repository")
public class EntityManagerDatasourceConfig {
private final DataSource dataSource;
/**
* Defines project specific entity manager configurations for Hibernate including table auto-generation
* and overriding & replace audit table suffix etc.
* @return javax.persistence.EntityManagerFactory
*/
@Bean(name = "entityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceProvider(new HibernatePersistenceProvider());
em.setPackagesToScan("com.cloudofgoods.notification.entity");
em.setDataSource(dataSource);
Properties properties = new Properties();
properties.setProperty("org.hibernate.envers.audit_table_suffix", "_hst"); // Overrides Audit table suffix of "_AUD" to "_hst"
// properties.setProperty("hibernate.hbm2ddl.auto", "update"); // Note:- Uncomment only when needed to manually update table structure for development purpose
em.setJpaProperties(properties);
em.afterPropertiesSet();
return em.getObject();
}
}
So, we're all set with EntityManagerFactory class as per the above mentioned changes. However only the above changes will't do the trick for auditing. So, we've to instruct the each entity class which we need to get Audited, with @Audited annotation (org.hibernate.envers.Audited) as per the below piece of code.
import com.cloudofgoods.notification.enums.ActiveStatus;
import com.cloudofgoods.notification.enums.DevicePlatform;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.envers.Audited;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
@Audited
@Getter
@Setter
@Entity
@Table(name = "notification")
public class Notification implements Serializable {
private static final long serialVersionUID = 3655675803974923350L;
@Id
@Column(name = "notification_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "firebase_client_token")
private String token;
@Enumerated(EnumType.STRING)
@Column(name = "platform")
private DevicePlatform platform;
@Enumerated(EnumType.STRING)
@Column(name = "status")
private ActiveStatus activeStatus;
@Column(name = "last_updated_date_time")
private Timestamp lastUpdatedDateTime;
@Column(name = "last_updated_user")
private String lastUpdatedUser;
}
So, now we're all set to go with the implementation. If we execute our application after doing these modifications, we can see the audit tables are generated automatically by the EntityManagerFactory which we configured earlier along with the property configuration we applied as well.
Furthermore when we perform any changes to the database table through the JPA entity all the table modifications'll be applicable to the audit table as well.
Keywords: Audit Table Audit Table Generation Audit Table Implementation Hibernate JPA Hibernate vs JPA EntityManagerFactory Hibernate Envers DDL Auto Update Table Auto Update hibernate.hbm2ddl.auto org.hibernate.envers.audit_table_suffix @EnableJpaRepositories @Audited Java
0Comments