Background

在一些数据敏感的项目, 特别是配置表, 我们需要记录每一次对表的甚至每个值的改动, 并把改动的数据存放到另一张表中。

以前我们可能会用数据库trigger来实现, 但trigger实现方式也有如下限制

  1. 需要用sql编写trigger, 一但表结构更改, 需要找人修改trigger
  2. 手动创建Audit 表
  3. 对删除(hard delete)难以detect是谁删除的。

当今世界, 更加偏向用java框架去实现,例如JPA Audit 和 Hiberate Envers

JPA Audit

如果对Audit 的要求不高, 只需要在表中记录是谁创建的, 谁最后修改,创建时间和最后修改时间。
这种情况下我们使用JPA Audit就足够了。

下面来看是怎么实现的, 我们会用user service 作为例子.

step 1, 对Entity类添加注解 @EntityListeners(AuditingEntityListener.class)

@Entity // to be pojo class of Hibernate
@Data
@Table(name = "tb_user")
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class User {

step 2, 对Entity类添加 下面4个关于audit的属性

    @CreatedDate@JsonIgnoreprivate Date createDate;@LastModifiedDate@JsonIgnoreprivate Date lastModifiedDate;@CreatedBy@JsonIgnoreprivate String createdBy;@LastModifiedBy@JsonIgnoreprivate String lastModifiedBy;

step 3, 添加1个bean,实现AuditorAware接口告诉JPA当前的用户是谁

正常呢来讲, username should be get from Sprint security API, 为了测试方便这边我就hardcode了

import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;import java.util.Optional;@Component("myAuditorAware")
public class MyAuditorAware implements AuditorAware<String> {@Overridepublic Optional<String> getCurrentAuditor() {return Optional.of("JasonPoon");}
}

step 4, 在启动类添加注解 @EnableJpaAuditing(auditorAwareRef = “myAuditorAware”)

@EnableJpaRepositories
@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "myAuditorAware")
@ComponentScan({"cn.home.user.config","cn.home.user.web","cn.home.user.service","cn.home.user.pojo","cn.home.user.dao"})
public class UserApplication {public static void main(String[] args) {SpringApplication.run(UserApplication.class, args);}
}

step 5, 接下来我们就可以测试了

@Slf4j
@DataJpaTest //default will auto rollback
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class UserDaoTest {@Autowiredprivate UserDao userDao; //springboot will create an instance of the interface while starting@Test@DisplayName("test add User")@Rollback(value = false)public void testAddUser(){User user = new User();user.setUsername("Alice13");user.setAddress("The 5th School");userDao.save(user);log.info("User id: {}",user.getId());assertTrue(0 < user.getId(),"id should be generated");userDao.delete(user);}@Test@DisplayName("test add User")@Rollback(value = false)public void updateUser(){User user = userDao.findByUsername("Alice12");log.info("User id: {}",user.getId());user.setAddress("The 5th School3");userDao.save(user);assertTrue( "The 5th School3".equals(user.getAddress()),"address should be updated");}@Test@DisplayName("find one User")@Rollback(value = false)public void findUserTest1(){User user = userDao.findByUsername("Alice12");log.info(String.valueOf(user));assertNotNull(user);}}

如果enable了 spring.jpa.hibernate.ddl-auto=true, 启动时, 会自动为tb_user表添加create_date等4个列。

测试pass时检查下record
可以看见audit 信息已经被加入!

Hibernate Envers

如果对某张表的要求比较高, 要记录所有的change History在另1 张table, 这时我们需要用到Hibernate Envers
下面也是对user service 的 user table作一个例子.

首先我们Enver需要一张公共表 revinfo

默认情况下,它包含两列
REV- 主键列 - 修订版ID/修订版号
REVTSTMP- 修订版创建的时间戳。

而且Envers 会建立hard 外键 在其他Audit表上, 所以db 账号必须具有创建外键 REFERENCES 的权限。
Mysql 中, grant语句是:

grant select,insert,update,delete,create,alter,drop,REFERENCES on demo_cloud_user.* to cloud_user;

step 1, 添加hibernate-envers 依赖

         <dependency><groupId>org.hibernate</groupId><artifactId>hibernate-envers</artifactId></dependency>

step 2, 在springboot 配置文件中, 添加关于envers的属性

spring:datasource:url: jdbc:mysql://43.138.222.61:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: cloud_userpassword: '{cipher}323e2265acd321eaec76a88bfa710f5f3673c58f8e6e1bbe2944f08b9518ac0c'driver-class-name: com.mysql.cj.jdbc.Driverhikari:maxLifeTime: 30000jpa:show-sql: truegenerate-ddl: truehibernate:ddl-auto: updateproperties:hibernate:dialect: org.hibernate.dialect.MySQL8Dialectorg:hibernate:envers:audit_strategy: org.hibernate.envers.strategy.internal.DefaultAuditStrategyaudit_strategy_validity_store_revend_timestamp: true

其中audit_strategy, org.hibernate.envers.strategy.internal.DefaultAuditStrategy 的意思为
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更快一些

具体的Envers 设置, 请参考
https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#envers

step 3, 在springboot 配置文件中, 添加关于envers的属性

在Entity类上加上@Audited 注解


@Entity // to be pojo class of Hibernate
@Data
@Table(name = "tb_user")
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@Audited
public class User {

接下来就可以测试了

执行上面的都测试用例, 可以见到1个新的AUD表被创建

JPA Audit and Envers相关推荐

  1. JPA EnableJpaAuditing 审计功能

    关于自动填充或更新实体中的 CreateDate.CreatedBy 等在之前有一篇 jeecg 默认为空的字段值是如何被填充的? 有提到通过拦截器的方式实现,但是今天带大家了解一下如果使用 JPA ...

  2. java 持久化线程_java – Spring Hibernate Envers多线程 – 会话关...

    我们使用Hibernate(使用JPA)和Hibernate Envers来持久化对象的历史. Web应用程序运行许多线程,其中一些是通过其他应用程序的RMI方法调用创建的,其中一些是由应用程序本身创 ...

  3. Spring Roo 简介

    一直以来,Java/Spring开发被认为是笨重的代表,无法快速生成项目原型和骨架.所以,Spring推出了Spring Roo这个项目,帮助我们快速生成项目原型.本文参考自Spring Roo的官方 ...

  4. hibernate envers实践总结

    1.简介 Envers模块是一个核心的Hibernate模型,可与Hibernate和JPA一起使用.事实上,你可以在Hibernate工作的任何地方使用Envers,无论它是独立的,在WildFly ...

  5. 如何使用Hibernate Envers审核数据,包括用户名信息

    最近,我一直在一个项目中工作,该项目需要审核所有数据库事务,包括用户名.为此,我一直在使用Hibernate ORM Envers,它旨在实现持久类的简单审计/版本控制. 为了在这篇文章中展示如何使用 ...

  6. JPA在MySQL中自动建表

    为什么80%的码农都做不了架构师?>>>    JPA(Java Persistence API)是Spring Boot访问关系型数据库的一个标准接口,它使用ORM(Object- ...

  7. Spring Data JPA 从入门到精通~Auditing及其事件详解

    Auditing 及其事件详解 Auditing 翻译过来是审计和审核,Spring 的优秀之处在于帮我们想到了很多繁琐事情的解决方案,我们在实际的业务系统中,针对一张表的操作大部分是需要记录谁什么时 ...

  8. Spring系列学习之Spring Data Envers数据访问

    英文原文:https://spring.io/projects/spring-data-envers 目录 概述 快速开始 学习 文档 概述 该项目是Spring Data JPA项目的扩展,允许访问 ...

  9. Java数据审计工具:Envers and JaVers比较

    在Java世界中,有两种数据审计工具:Envers和JaVers. Envers已经存在了很长时间,它被认为是主流. JaVers提供全新的方法和技术独立性. 如果您考虑哪种工具更适合您的项目,本文是 ...

最新文章

  1. server.mapPath(.mdb)
  2. JNI 返回 jbyteArray
  3. aide怎么打开html文件,求助!aide获取网页html源码
  4. arm02gnu/linux,2.1. 支持的硬件 - Debian GNU/Linux 安装手册(PPC架构)
  5. 数字图像基础(二进制图像、灰度图像、RGB图像、索引图像和多帧图像)
  6. 【JavaSE03】Java中分支语句-练习
  7. 东北师范大学计算机学院的导师,东北师范大学计算机科学与信息技术学院研究生导师简介-王佳男...
  8. 判断回文递归算法实现
  9. jvisualvm离线安装visualgc插件
  10. 彻底分析ARP病毒查杀防范全攻略
  11. win11联网不能打开网页怎么办 windows11联网不能打开网页的解决方法
  12. Oracle truncate table 与 delete tabel的区别
  13. java-ActiveXComponent调用com组件
  14. 服装尺寸 html,史上最完整的服装尺寸号型和换算知识
  15. ES6 模板字符串基本用法
  16. 操作系统安装磁盘清理方法
  17. 3D游戏建模学习有哪些书?自学难不难?能学成就业吗
  18. 性能测试入门(一):性能测试中的各项指标告诉我们什么
  19. 诺贝尔奖得主纳什夫妇因车祸去世
  20. 第十部分 项目风险管理

热门文章

  1. 城市简码_在WordPress中使用简码的7个基本技巧
  2. 为何我们总难听进别人的话
  3. 東京喰種_经典台词中日双语1
  4. 计算的极限(六):无穷的彼岸
  5. 2017湖北计算机二级准考证打印入口,2017年全国计算机二级准考证打印网址.doc
  6. iOS 新建本地数据库FMDB
  7. 计算机芯片制造的主要材料是什么,芯片是什么材料,芯片制造过程图解及用途分享...
  8. 日食月食Java_2018年日食和月食时间,两次月食三次日食(我国可见三次)
  9. CSAPP实验——逆向工程拆除“二进制炸弹”程序
  10. 微信公众号被封怎么办