Spring Data Jpa 审计功能

本文介绍了Spring Data Jpa的审计功能,重点讲解了@LastModifiedDate和@CreatedDate两个注解的使用。通过启用JPA审计,实体监听器和数据库表的设计,展示了如何在保存和更新操作中自动维护创建和修改时间。然而,当使用JPQL更新数据时,@LastModifiedDate注解可能失效,解决方案是在更新语句中显式设置当前时间。

  Spring Data Jpa的审计功能需要引入下述依赖 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.4.2</version>
</dependency>

Spring Data Jpa提供4个审计注解:@CreatedBy、@LastModifiedBy、@CreatedDate 和@LastModifiedDate

下述仅仅学习@CreatedDate和@LastModifiedDate两个注解

第一种:@LastModifiedDate

 第一步:启动类中添加@EnableJpaAuditing注解表示启用JPA审计

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

第二步: 数据库中创建表tb_user

CREATE TABLE `tb_user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(32) NOT NULL COMMENT '姓名',
  `age` int NOT NULL COMMENT '年龄',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) COMMENT='用户表';

第三步: 在实体中添加注解 @EntityListeners(AuditingEntityListener.class) 监听实体变化,并且在updateTime字段上增加 @LastModifiedDate注解

import lombok.Data;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

@EntityListeners(AuditingEntityListener.class)
@Data
@Entity
@Table(name = "tb_user")
public class TbUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private Integer age;

    @Column(name = "create_time")
    private Date createTime;

    @LastModifiedDate
    @Column(name = "update_time")
    private Date updateTime;
}

第四步:往表tb_user中插入一行记录

INSERT INTO `tb_user` (`id`, `name`, `age`, `create_time`, `update_time`) VALUES('1','张三','18','2021-11-09 00:00:00',NULL);

第五步:构建测试代码去测试@LastModifiedDate注解

import com.bc.single.dao.UserDao;
import com.bc.single.entity.TbUser;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
class ApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void contextLoads(){
        TbUser user=userDao.findAll().get(0);
        user.setName("李四");
        userDao.save(user);
    }
}

执行上述测试后,就会发现数据库中该条数据的update_time字段值已经自动产生了

特别提示:如果是使用JPA的save(实体)方法去更新数据,@LastModifiedDate注解使用是没有问题的。如果是使用SQL/JPQL语句去更新数据,@LastModifiedDate注解的使用就会失效,例如我们在UserDao中构建一个JPQL更新操作语句updateTest:

import com.bc.single.entity.TbUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface UserDao extends JpaRepository<TbUser,Integer> {

    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update TbUser set name ='王五' where id=:id")
    void updateTest(@Param("id") Integer id);
}

 测试类中的测试方法如下:

import com.bc.single.dao.UserDao;
import com.bc.single.entity.TbUser;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
class ApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void contextLoads(){
        userDao.updateTest(1);
    }
}

执行上述结果后,其结果为:

可以看到使用上述JPQL更新操作语句时,@LastModifiedDate注解已经失效了。针对这种情况,最简单的解决办法,就是在JPQL更新操作语句里对updateTime字段赋值current_time即可。

import com.bc.single.entity.TbUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface UserDao extends JpaRepository<TbUser,Integer> {

    @Transactional(rollbackFor = Exception.class)
    @Modifying
    @Query("update TbUser set name ='王五',updateTime=current_time where id=:id")
    void update(@Param("id") Integer id);
}

第二种:@CreatedDate

在上述实体类的基础之上,在实体类的createTime字段上增加 @CreatedDate注解

import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

@EntityListeners(AuditingEntityListener.class)
@Data
@Entity
@Table(name = "tb_user")
public class TbUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private Integer age;

    @CreatedDate
    @Column(name = "create_time")
    private Date createTime;

    @LastModifiedDate
    @Column(name = "update_time")
    private Date updateTime;
}

在测试类中创建新对象进行保存:

import com.bc.single.dao.UserDao;
import com.bc.single.entity.TbUser;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
class ApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void contextLoads(){
        TbUser user=new TbUser();
        user.setName("赵六");
        user.setAge(18);
        userDao.save(user);
    }
}

数据库中的数据记录如下: 

可以看到在新增一条记录的时候,create_time和update_time字段都会自动赋值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值