欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Data Jpa的@DynamicInsert注解和@DynamicUpdate注解

程序员文章站 2022-04-23 22:10:20
...

当前引入的Spring Data Jpa的版本为2.4.2


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

 构建的数据库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 DEFAULT NOW() COMMENT '创建时间',
  `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) COMMENT='用户表';

第一种:@DynamicInsert

当我们不为实体类中添加@DynamicInsert注解时:

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

@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;

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

 构建测试类进行insert插入测试:

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);
    }
}

执行上述单元测试以后,在控制台中查看Hibernate日志打印的SQL:

insert into tb_user (age, create_time, name, update_time) values (?, ?, ?, ?)

然后查看tb_user表中的数据,这时会发现虽然我们在创建表结构的时候已经定义了create_time字段的默认值为now(),但是很明显该配置没有生效。这是由于使用Jpa的save()方法在保存一个对象实体的时候,即使这个字段的值为null,仍然会加入到insert语句中。

Spring Data Jpa的@DynamicInsert注解和@DynamicUpdate注解

如果在实体类中添加了@DynamicInsert注解,如下所示:

import lombok.Data;
import org.hibernate.annotations.DynamicInsert;
import javax.persistence.*;
import java.util.Date;

@DynamicInsert
@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;

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

 再次执行上述单元测试后,在控制台中查看Hibernate日志打印的SQL:

insert into tb_user (age, name) values (?, ?)

然后再次查看tb_user表中的数据,可以看到新增的一条数据中create_time字段的值已经被设定为系统当前日期时间:

Spring Data Jpa的@DynamicInsert注解和@DynamicUpdate注解

总结:@DynamicInsert注解的默认值为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句当中;如果将该注解的值设为false的话,则此配置不会生效。

适用场景:例如在数据库插入日期或时间戳字段时,在对象字段为空的情况下,希望表中的字段能自动填充为默认的值。

第二种:@DynamicUpdate

当我们不为实体类中添加@DynamicUpdate注解时:

package com.bc.single.entity;

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

@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;

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

 构建测试类进行update插入测试:

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.setAge(19);
        userDao.save(user);
    }
}

执行上述单元测试以后,在控制台中查看Hibernate日志打印的SQL:

update tb_user set age=?, create_time=?, name=?, update_time=? where id=?

可以看出其实我们仅仅想更新的是age字段,但是Jpa却将把对象的属性字段全部给更新了。

如果在实体类中添加了@DynamicUpdate注解,如下所示:

import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
import java.util.Date;

@DynamicUpdate
@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;

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

再次执行上述单元测试后,在控制台中查看Hibernate日志打印的SQL:

update tb_user set age=? where id=?

此时Jpa仅仅针对age字段进行更新,已经达到了预期的效果。

总结:在更新表时,如果仅仅想更新某个字段,可以考虑加上@DynamicUpdate注解,这样在更新表时速度会相对比较快一点