Spring Data JPA的Audit功能审计数据库的变更

我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶!

1 数据库审计

数据库审计是指当数据库有记录变更时,可以记录数据库的变更时间和变更人等,这样以后出问题回溯问责也比较方便。对于审计表记录的变更可以两种方式,一种是建立一张审计表专门用于记录,另一种是在数据库增加字段。本文所讨论的是第二种方案。

那如何在新增、修改、删除的时候同时增加记录呢?如果每张表都单独记录,代码就会显得很冗余。更好的方式应该是做切面或者事件监听,当数据有变更时统一进行记录。

2 Spring Data JPA审计

Spring Data JPA为我们提供了方便的Audit功能,通过四个注解来标记字段:

(1) @CreatedBy: 创建人

(2) @CreatedDate: 创建时间

(3) @LastModifiedBy: 最后修改人

(4) @LastModifiedDate: 最后修改时间

接下来我们来看看怎么使用。

2.1 项目准备

通过Docker启动PostgreSQL数据库:

docker run -itd \
    --name pkslow-postgres \
    -e POSTGRES_DB=pkslow \
    -e POSTGRES_USER=pkslow \
    -e POSTGRES_PASSWORD=pkslow \
    -e PGDATA=/var/lib/postgresql/data/pgdata \
    -p 5432:5432 \
    postgres:10

引入相关依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Spring Security不是必须的,这里使用它来获取用户名。配置的用户为:

spring.security.user.name=pkslow
spring.security.user.password=123456

2.2 创建实体父类

其实父类不是必须的,你可以在每个想Audit的实体类进行配置,但比较麻烦,不如创建一个父类,再让想审计的子类都继承它:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Auditable<U> {
    @CreatedBy
    @Column(name = "created_by")
    private U createdBy;

    @CreatedDate
    @Column(name = "created_date")
    private Date createdDate;

    @LastModifiedBy
    @Column(name = "last_modified_by")
    private U lastModifiedBy;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    private Date lastModifiedDate;
  // getter
  //setter
}

@MappedSuperclass可以让其它子实体类继承相关的字段和属性;

@EntityListeners设置监听类,会对新增修改进行回调处理。

有了父类之后,子类就简单了:

@Entity
@Table(name = "pkslow_users")
public class User extends Auditable<String> {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long userId;
    private String name;
    private String email;
    private String country;
    private String website;
  //getter setter
}

2.3 如何获取名字

数据总是被修改的,我们要提供一个获取修改人名字的接口,配置如下:

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfiguration {

    @Bean
    public AuditorAware<String> auditorProvider() {
        return () -> {
            String username = "system";
            SecurityContext context = SecurityContextHolder.getContext();
            if (context != null) {
                Authentication authentication = context.getAuthentication();
                if (authentication != null) {
                    username = authentication.getName();
                }
            }

            String result = username;
            return Optional.ofNullable(result);
        };
    }
}

这里配置的是通过Spring SecurityContext来获取登陆用户的名字,当然可以有其它方案,如获取请求头的某个字段等。

注意注解@EnableJpaAuditing开启了审计功能。

2.4 测试

我们通过一个Controller来新增数据,看看会有什么效果:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserRepository userRepository;
    @PostMapping
    public User save(@RequestBody User user) {
        return userRepository.save(user);
    }
}

通过curl命令来测试如下:

$ curl 'http://localhost:8088/user' -X POST \
> -H 'Content-Type: application/json' \
> -H 'Authorization:Basic cGtzbG93OjEyMzQ1Ng==' \
> -d '{
>     "name":"larry",
>     "email":"admin@pkslow.com",
>     "country":"China",
>     "website":"www.pkslow.com"
> }'
{"createdBy":"pkslow","createdDate":"2021-01-15T15:08:47.035+0000","lastModifiedBy":"pkslow","lastModifiedDate":"2021-01-15T15:08:47.035+0000","userId":7,"name":"larry","email":"admin@pkslow.com","country":"China","website":www.pkslow.com}

查看数据库,已经生成了审计记录:

3 总结

代码请查看:https://github.com/LarryDpk/pkslow-samples

到此这篇关于Spring Data JPA的Audit功能审计数据库的变更的文章就介绍到这了,更多相关Spring Data JPA审计数据库变更内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-06-23

Spring Data Jpa 自动生成表结构的方法示例

想在部署的时候随应用的启动而初始化数据脚本,这不就是Spring Data Jpa中的自动生成表结构,听起来特别简单,不就是配置Hibernate的ddl-auto嘛,有什么好说的,是个人都知道.当初我也是这样认为,实际操作了一把,虽然表是创建成功了,但是字段注释,字符集以及数据库引擎都不对,没想到在这些细节上翻车了. 毕竟开翻的车还要自己扶起来,于是在这记录一下. 注:本文中使用的Spring Data Jpa版本为2.1.4.RELEASE 以MySQL为例,我这边举个例子: import

Spring Data JPA 建立表的联合主键

最近遇到了一个小的问题,就是怎么使用 Spring Data JPA 建立表的联合主键?然后探索出了下面的两种方式. 第一种方式: 第一种方式是直接在类属性上面的两个字段都加上 @Id 注解,就像下面这样,给 stuNo 和 stuName 这两个字段加上联合主键: @Entity @Table(name = "student") public class Student { @Id @Column(name = "stu_no", nullable = false

Spring Boot中使用Spring-data-jpa实现数据库增删查改

在实际开发过程中,对数据库的操作无非就"增删改查".就最为普遍的单表操作而言,除了表和字段不同外,语句都是类似的,开发人员需要写大量类似而枯燥的语句来完成业务逻辑. 为了解决这些大量枯燥的数据操作语句,我们第一个想到的是使用ORM框架,比如:Hibernate.通过整合Hibernate之后,我们以操作Java实体的方式最终将数据改变映射到数据库表中. 为了解决抽象各个Java实体基本的"增删改查"操作,我们通常会以泛型的方式封装一个模板Dao来进行抽象简化,但是这

springboot使用spring-data-jpa操作MySQL数据库

我们在上一篇搭建了一个简单的springboot应用,这一篇将介绍使用spring-data-jpa操作数据库. 新建一个MySQL数据库,这里数据库名为springboot,建立user_info数据表,作为我们示例操作的表对象. user_info信息如下: DROP TABLE IF EXISTS `user_info`; CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(

Spring boot中使用Spring-data-jpa方便快捷的访问数据库(推荐)

什么是JPA JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.他的出现主要是为了简化现有的持久化开发工作和整合ORM技术 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA

SpringBoot Data JPA 关联表查询的方法

SpringBoot Data JPA实现 一对多.多对一关联表查询 开发环境 IDEA 2017.1 Java1.8 SpringBoot 2.0 MySQL 5.X 功能需求 通过关联关系查询商店Store中所有的商品Shop,商店对商品一对多,商品对商店多对一,外键 store_id存在于多的一方.使用数据库的内连接语句. 表结构 tb_shop tb_store 实体类,通过注解实现 1.商店类Store.java package com.gaolei.Entity; import ja

Mongodb实现的关联表查询功能【population方法】

本文实例讲述了Mongodb实现的关联表查询功能.分享给大家供大家参考,具体如下: Population MongoDB是非关联数据库.但是有时候我们还是想引用其它的文档.这就是population的用武之地. Population是从其它文档替换文档中的特定路径.我们可以迁移一个单一的文件,多个文件,普通对象,多个普通的对象,或从查询中返回的所有对象 populate 方法 populate 方法可以用在 document 上. model 上或者是 query 对象上,这意味着你几乎可以在任

MyBatis学习教程(五)-实现关联表查询方法详解

一.一对一关联  1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系. CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name VARCHAR() ); CREATE TABLE class( c_id INT PRIMARY KEY AUTO_INCREMENT, c_name VAR

Yii中CGridView关联表搜索排序方法实例详解

本文实例讲述了Yii中CGridView关联表搜索排序方法.分享给大家供大家参考.具体实现方法如下: 在Yii CGridView 关联表搜索排序实现方法有点复杂,今天看了一老外写的了篇游戏,下面我整理一下与各位朋友分享一下,相信会对大家Yii框架的学习有所帮助. 首先,检查你的blog demo里的protectedmodelsComment.php,确保Comment模型有一个search的方法,如果没有,就用gii生成一个,我下载到的blog demo里倒是没有. 然后,写代码的时间到了,

SQLServer批量更新两个关联表数据的方法

本文实例讲述了SQLServer批量更新两个关联表数据的方法.分享给大家供大家参考,具体如下: 方式1: UPDATE a SET WtNo=b.NO from WT_Task a INNER JOIN WT_BasicInformation b ON a.WtId=b.ID; 方式2: UPDATE a SET a.WtNo=b.NO FROM WT_Task a,WT_BasicInformation b WHERE a.WtId=b.ID; 希望本文所述对大家SQL Server数据库程序

Django ManyToManyField 跨越中间表查询的方法

1.在 django 表中用到了 manytomany 生成了中间表 pyclub_article_column from django.db import models # Create your models here. class Column(models.Model): id = models.AutoField(u'序号',primary_key=True,auto_created=True) name = models.CharField(u'名字',max_length=100)

thinkPHP框架实现多表查询的方法

本文实例讲述了thinkPHP框架实现多表查询的方法.分享给大家供大家参考,具体如下: 我们可以将两个表连起来一起查询数据,我现在有两张表,一个是feedback表和member表,如图: 总目录: 上代码: $where = array(); $where['meiyepin_feedback.member_id'] = "1"; $Model = M('feedback'); $a = $Model ->join('meiyepin_member ON meiyepin_fe

Spring Data JPA实现动态查询的两种方法

前言 一般在写业务接口的过程中,很有可能需要实现可以动态组合各种查询条件的接口.如果我们根据一种查询条件组合一个方法的做法来写,那么将会有大量方法存在,繁琐,维护起来相当困难.想要实现动态查询,其实就是要实现拼接SQL语句.无论实现如何复杂,基本都是包括select的字段,from或者join的表,where或者having的条件.在Spring Data JPA有两种方法可以实现查询条件的动态查询,两种方法都用到了Criteria API. Criteria API 这套API可用于构建对数据

详解Spring Data JPA动态条件查询的写法

我们在使用SpringData JPA框架时,进行条件查询,如果是固定条件的查询,我们可以使用符合框架规则的自定义方法以及@Query注解实现. 如果是查询条件是动态的,框架也提供了查询接口. JpaSpecificationExecutor 和其他接口使用方式一样,只需要在你的Dao接口继承即可(官网代码). public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecification