How do you implement auditing/versioning for entities in Hibernate?
🔎 Option 1: Hibernate Envers (recommended)
Envers is built into Hibernate → it provides automatic auditing of entity changes without requiring manual code to persist history.
How it works:
- Envers creates an audit table for each audited entity, e.g.,
my_entity_AUD. - Every time an entity changes, Envers stores a new version in the audit table.
- You can query historical states easily.
Steps to use Envers:
✅ 1) Add Envers dependency:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
✅ 2) Annotate entities with @Audited:
@Entity
@Audited
public class Order {
@Id
private Long id;
private String status;
private double amount;
}
| REV | REVTYPE | ID | STATUS | AMOUNT |
|---|---|---|---|---|
| 1 | 0 | 42 | NEW | 100.0 |
| 2 | 1 | 42 | PAID | 100.0 |
REVTYPE tells the change type: 0=INSERT, 1=UPDATE, 2=DELETE.
✅ 4) Query historical data:
AuditReader reader = AuditReaderFactory.get(entityManager);
Order oldOrder = reader.find(Order.class, 42L, 1); // revision 1
🔎 Option 2: Manual auditing (simpler but limited)
✅ Add fields to your entity:
@Entity
public class Order {
@Id
private Long id;
private String status;
private double amount;
private String createdBy;
private LocalDateTime createdAt;
private String updatedBy;
private LocalDateTime updatedAt;
}
✅ Use JPA callbacks or Spring’s @EntityListeners to set audit fields automatically:
@PrePersist
public void onCreate() {
createdAt = LocalDateTime.now();
createdBy = getCurrentUser();
}
@PreUpdate
public void onUpdate() {
updatedAt = LocalDateTime.now();
updatedBy = getCurrentUser();
✅ This approach only tracks the latest change, not full history.
🔎 Option 3: Interceptors or event listeners
For more control, Hibernate’s Interceptor or EventListener lets you capture every entity operation globally.
Example with Interceptor:
public class AuditInterceptor extends EmptyInterceptor {
@Override
public boolean onFlushDirty(
Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] types) {
if (entity instanceof AuditableEntity) {
// set updatedBy, updatedAt, etc.
}
return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}
}
📌 Key Takeaways
✅ Use Hibernate Envers for robust, out-of-the-box entity versioning → supports easy history querying.
✅ Use manual audit fields with listeners for simpler created/updated tracking.
✅ Advanced: interceptors or event listeners let you customize auditing globally.