Spring Data Jpa的@DynamicInsert注解和@DynamicUpdate注解
当前引入的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语句中。
如果在实体类中添加了@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字段的值已经被设定为系统当前日期时间:
总结:@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注解,这样在更新表时速度会相对比较快一点
推荐阅读
-
详解Spring Data JPA使用@Query注解(Using @Query)
-
Spring-Data-JPA整合MySQL和配置的方法
-
Spring框架中 @Autowired 和 @Resource 注解的区别
-
Spring 中 @Service 和 @Resource 注解的区别
-
品Spring:对@Autowired和@Value注解的处理方法
-
浅谈Spring中@Import注解的作用和使用
-
详解Spring Data JPA使用@Query注解(Using @Query)
-
Spring-Data-JPA整合MySQL和配置的方法
-
Spring框架中 @Autowired 和 @Resource 注解的区别
-
@Autowired 和 @Resource注解, 一个接口有多个实现类的时候Spring注入遇到的问题