红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 专栏
  3. Spring Boot 学习笔记
  4. 正文

从零开始 Spring Boot 54:@NotNull in Entity

2023年6月30日 947点热度 0人点赞 0条评论

spring boot

图源:简书 (jianshu.com)

之前通过两篇文章介绍了 Hibernate Validation 在 Spring 中的应用:

  • 从零开始 Spring Boot 13:参数校验 - 红茶的个人站点 (icexmoon.cn)

  • 从零开始 Spring Boot 30:数据校验 - 红茶的个人站点 (icexmoon.cn)

实际上这些的数据校验注解也可以在 JPA 的实体类中使用,本文会展示如何在实体类中使用@NotNull注解用于数据校验,以及其和@Column注解的异同。

@NotNull

先看实体类:

// ...
public class Student4 {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @EqualsAndHashCode.Include
    private Long id;
​
    @NotNull
    @Column(length = 25)
    private String name;
​
    @NotNull
    @Column(length = 50)
    private String address;
​
    @Convert(converter = ContactsConverter.class)
    @Column(columnDefinition = "text")
    private Contacts contacts;
​
    public Student4() {
​
    }
}

这个实体类中的name和address属性并没有用之前用过的@Column(nullable=false),而是使用了 Hibernate Validation 的@NotNull注解。

看效果:

@Test
void addStudentWithValidation() {
    Student4 s = new Student4.Student4Builder()
        .build();
    Assertions.assertThrows(TransactionSystemException.class, () -> {
        student4Repository.save(s);
    });
}

如果添加实体的时候用@Notnull标记的属性为null,就会抛出一个TransactionSystemException异常,并提示"xxx不能为null"。通过观察输出的日志可以发现,并没有 Hibernate 执行 INSERT SQL 的相关日志,说明根本没有执行相关的 SQL 就已经退出。

实际上 Hibernate 会在@PrePersist事件中对使用 Hibernate Validation 相关注解的属性进行验证,如果不通过,就抛出异常并终止。

实际上使用@NotNull注解还有一个额外好处——Hibernate 可以帮助我们在 DDL 中将相应的字段设置为not null:

CREATE TABLE `user_student4` (
  `id` bigint NOT NULL,
  `address` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
  `contacts` text COLLATE utf8mb4_general_ci,
  `name` varchar(25) COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

如果你不需要让 Hibernate 自动使用 Validation 相关注解修改 DDL 语句,可以:

spring.jpa.properties.hibernate.validator.apply_to_ddl=false

现在由 Hibernate 自动生成的 DDL 中就不包含相应字段的not null了:

CREATE TABLE `user_student4` (
  `id` bigint NOT NULL,
  `address` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `contacts` text COLLATE utf8mb4_general_ci,
  `name` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

比较奇怪的是有一个DEFAULT NULL。

@Column(nullable=false)

我们知道,使用@Column(nullable=false)会让生成的 DDL 语句中包含not null,并在 Hibernate 执行 INSERT SQL 时才会发挥作用(如果相应的字段为null就会报错)。

实际上这并不完全正确,只能说默认的情况如此。但是,我们可以通过设置属性让 Hibernate 在执行 INSERT 语句前也进行类似的数据校验:

spring.jpa.properties.hibernate.check_nullability=true

实体类:

// ...
public class Student3 {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @EqualsAndHashCode.Include
    private Long id;
​
    @Column(length = 25, nullable = false)
    private String name;
​
    @Column(length = 50, nullable = false)
    private String address;
​
    @Convert(converter = ContactsConverter.class)
    @Column(columnDefinition = "text")
    private Contacts contacts;
​
    public Student3() {
​
    }
}

测试用例:

@Test
@SneakyThrows
void testAddNewStudentWithNull() {
    Student3 newStudent = Student3.builder()
        .address("宁安大街101号")
        .contacts(Contacts.builder()
                  .name("lalala")
                  .address("北京东路100号")
                  .phone("123456789")
                  .build())
        .build();
    Assertions.assertThrows(DataIntegrityViolationException.class, () -> {
        student3Repository.save(newStudent);
    });
}

此时在保存时,如果相应属性为null,会抛出一个DataIntegrityViolationException异常,并提示"xxx属性不能为null"。并且同样的,没有相应的 INSERT SQL 执行日志。

总结

可以看到,@NotNull和@Column(nullable=false)都可以起到相同的效果——在执行 SQL 前检查实体对象的相应属性是非为null,如果是就抛出异常。

相比较而言,使用@NotNull更方便一些(不用修改任何属性),并且我们可以使用 Hibernate Validation 的一系列注解来构建我们的验证逻辑,以确保保存到数据库的内容的合法性。

The End,谢谢阅读。

可以从这里获取本文的完整示例代码。

参考资料

  • Hibernate @NotNull vs @Column(nullable = false) | Baeldung

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: hivernate notnull spring
最后更新:2023年6月30日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号