Hibernate module for Entity Auditing
@Entity
public class Device {
@Id
private long id;
@Type(type = "text")
private String configuration;
public static Device of(long id, String configuration) { ... }
public long getId(){ ... }
public String getConfiguration(){ ... }
public void setId(long id){ ... }
public void setId(String configuration){ ... }
}
final long id = 1;
transactionTemplate.execute(status -> {
final Device device = Device.of(id, "configuration 1");
hibernate.getCurrentSession().merge(device);
});
// save it again, it changed configuration
transactionTemplate.execute(status -> {
final Device device = Device.of(id, "configuration 2");
hibernate.getCurrentSession().merge(device);
});
What was the previous configuration?
What was the configuration yesterday?
All the times whan a configuration change occurred?
"Dunno, LOL!"
"Dunno, LOL!"
"Dunno, LOL!"
@Entity
@Audited // <--------
public class Device {
@Id
private long id;
@Type(type = "text")
private String configuration;
public static Device of(long id, String configuration) { ... }
public long getId(){ ... }
public String getConfiguration(){ ... }
public void setId(long id){ ... }
public void setId(String configuration){ ... }
}
final long id = 1;
transactionTemplate.execute(status -> {
final Device device = Device.of(id, "configuration 1");
hibernate.getCurrentSession().merge(device);
});
// save it again, it changed configuration
transactionTemplate.execute(status -> {
final Device device = Device.of(id, "configuration 2");
hibernate.getCurrentSession().merge(device);
});
What was the previous configuration?
What was the configuration yesterday?
All the times whan a configuration change occurred?
long revision = auditReader.getCurrentRevision(Rev.class, true).getId() -2;
String configuration = auditReader.find(Device.class, id, revision).getConfiguration();
long revision = auditReader.getRevisionNumberForDate(yesterday);
String configuration = auditReader.find(Device.class, id, revision).getConfiguration();
auditReader.createQuery().forRevisionsOfEntity(Device.class, false, false)
.add(AuditEntity.id().eq(id))
.getResultList()
.stream()
.map(entityRevisionAndType -> ((Rev)entityRevisionAndType[1]).getTimestamp())
.collect(Collectors.toList());
* Can use for more complex things too, but either query time (hibernate) or complexity (sqlQueries) skyrockets.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>4.3.7.Final</version><!-- current hibernate version -->
</dependency>
@Bean
public LocalSessionFactoryBean localSessionFactoryBean(...) {
final Properties p = new Properties();
// default strategy doesn't mark validity end time of a revision
p.put("org.hibernate.envers.audit_strategy",
"org.hibernate.envers.strategy.ValidityAuditStrategy");
// some weird stuff happens if you delete and then recreate an entity
// with the same id without this set to true
p.put("org.hibernate.envers.allow_identifier_reuse", true);
// suffixes overrides ...
p.put("org.hibernate.envers.audit_table_suffix", "_auditing");
p.put("org.hibernate.envers.revision_field_name", "_revision");
p.put("org.hibernate.envers.revision_type_field_name", "_revision_type");
p.put("org.hibernate.envers.audit_strategy_validity_end_rev_field_name", "_revision_end");
// we needed this, but it's usually useless to audit it.
p.put("org.hibernate.envers.do_not_audit_optimistic_locking_field", false);
final LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// snip...
factoryBean.setHibernateProperties(p);
return factoryBean;
}
More here
@Entity
@RevisionEntity
public class Rev {
@Id
@GeneratedValue
@RevisionNumber
private long id;
@RevisionTimestamp
private long timestamp;
// snip getters, setters, hashcode, equals, toString
}
More here
(What we know we didn't try)