随着各行各业信息化发展,决策者们越来越意识到数据版本追踪的重要性,尤其是上市公司,数据对于他们尤为重要。考虑到研发成本,对重要表单数据支持页面级的修改历史查看、对所有业务数据支持DB级的版本查看是一个不错的选择。
对于使用了Spring框架的Java项目而言,Spring Data Envers就是一个非常适合做数据审计的组件。下面我们看看如何在项目中集成Spring Data Envers实现数据审计功能。
1. 加入spring data envers依赖,如果是spring boot/cloud项目版本号无需填写
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
</dependency>
2. 启动类加入@EnableJpaAuditing和@EnableEnversRepositories注解
3. 配置文件application.properties中增加以下配置:
spring.jpa.properties.org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.internal.ValidityAuditStrategy
spring.jpa.properties.org.hibernate.envers.audit_strategy_validity_store_revend_timestamp=true
配置补充说明:
hibernate提供了两种审计策略,分别是
org.hibernate.envers.strategy.internal.DefaultAuditStrategy
org.hibernate.envers.strategy.internal.ValidityAuditStrategy
如果使用DefaultAuditStrategy,USER_AUD表中不会有REVEND,REVEND_TSTMP两个字段,只会单纯的记录变更与版本
而使用ValidityAuditStrategy,在新增一条变更记录时,会更新上一条变更记录的REVEND,REVEND_TSTMP为当前的版本号以及变更时间
因为ValidityAuditStrategy除了插入新纪录还要更新旧的记录,所以插入速度会慢一点,但是因为提供了额外的信息,对于数据查询,速度则较DefaultAuditStrategy更快一些。
4. 在DB创建审计实体表,默认表名为:revinfo(可以自定义审计实体类修改这个表名)
create table revinfo
(
rev int not null primary key,
revtstmp bigint
)
5. 在需要数据审计的实体类或字段上加入@Audited(org.hibernate.envers)注解
1) 整个类上加入@Audited注解 (推荐方式),会对类中所有字段进行版本审计:
@Audited
@Entity
@Table(name = "demo")
public class Demo {
...
}
2) 在字段上加入@Audited,仅对加了注解的字段进行版本审计:
@Audited
@Column(name = "name", length = 100, nullable = false)
private String name;
6. Repository中继承RevisionRepository<T(数据实体类型),String(数据ID类型),Long(审计版本号类型)>
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.history.RevisionRepository;
public interface DemoRepository extends JpaRepository<Demo, String>, RevisionRepository<Demo, String, Long> {
}
7. 将下列JPA配置修改为update,这样启动项目的时候会自动为加入@Audited的业务表创建审计表(_aud结尾,如:demo表对应的审计表就是demo_aud)
spring.jpa.hibernate.ddl-auto=update
8. 启动项目,使用继承了RevisionRepository的repository对象进行保存数据,然后看看数据库对应的_aud表是否有数据产生,每一次数据变更操作会在这个_aud表生成一条记录。
public void save(String name) {
Demo demo = new Demo();
demo.setName(name);
demoRepository.save(demo);
}
9. Spring Data Envers提供了一些方便操作数据审计记录的方法,可以直接使用:
//根据数据id获取审计集合对象:
Revisions<Long, Demo> revisions = demoRepository.findRevisions(id);
//获取审计对象列表
List<Revision<Long, Demo>> revisionList = revisions.getContent();
//遍历审计列表,可以封装需要的业务对象列表
revisionList.forEach(revision -> {
//历史版本的实体对象
Demo dm = revision.getEntity();
//审计Meta信息
revision.getMetadata();
//数据操作时间
revision.getMetadata().getDelegate()).getTimestamp();
//操作类型:修改、插入、删除、未知
revision.getMetadata().getRevisionType();
});