ChatGPT解决这个技术问题 Extra ChatGPT

混淆:@NotNull 与 @Column(nullable = false) 与 JPA 和 Hibernate

当它们出现在@Entity 的字段/getter 上时,它们之间有什么区别? (我通过休眠保持实体)。它们各自属于什么框架和/或规范? @NotNull 位于 javax.validation.constraints 中。在 javax.validation.constraints.NotNull javadoc 中,它说注释元素不能为空,但它没有说明元素在数据库中的表示,那么为什么我要在列中添加约束 nullable=false 呢?


C
Chakkakuru

@NotNull 是一个 JSR 303 Bean Validation 注释。它与数据库约束本身无关。然而,由于 Hibernate 是 JSR 303 的参考实现,它智能地获取这些约束并将它们转换为您的数据库约束,因此您以一个的价格获得两个。 @Column(nullable = false) 是 JPA 将列声明为非空的方式。即前者用于验证,后者用于指示数据库模式详细信息。您只是从 Hibernate 获得了一些关于验证注释的额外(欢迎!)帮助。


谢谢!因此,如果我希望我的 JPA 持久性不与 Hibernate 实现绑定(即更改为 EJB3),那么我必须同时使用两个注释(在字段及其列中禁止 null)?
我不知道。没有规范说 JPA 提供者必须识别 JSR 303 注释,但这并不意味着其他提供者不能。我不能说是否有人这样做或没有。
JPA 提供者不需要提供 JSR303 实现,但根据规范要求提供与任何第三方 JSR303 实现集成的能力。因此,尽管 Hibernate 确实提供了 JSR303,但您可以出于任何原因决定不使用他们的并与其他人一起使用,或者使用诸如 openJPA 之类的 JPA 实现并使用其他人提供 JSR303。另请注意,Hibernate 的 JPA 实现也是 EJB3。说是不正确的'如果我希望我的 JPA 持久性不与 Hibernate 实现绑定(即更改为 EJB3)' JPA 是 EJB3 规范的一部分。
@Shahzeb:问题不在于谁支持/提供 JSR 303 验证。它是关于哪些 ORM 能够识别 JSR 303 注释,如 @NotNull@Size@Min@Max 等,并将它们转换为数据库约束。
是的,但我的评论在 OP 在您不知道的后续评论中提出的内容中是有效的。
K
Kalle Richter

最新版本的休眠 JPA 提供程序默认将 bean 验证约束 (JSR 303) 像 @NotNull 应用于 DDL(感谢 hibernate.validator.apply_to_ddl property 默认为 true)。但是不能保证其他 JPA 提供者会这样做,甚至有能力这样做。

您应该使用像 @NotNull 这样的 bean 验证注释来确保在 JVM 中验证 java bean 时将 bean 属性设置为非空值(这与数据库约束无关,但在大多数情况下应该与它们相对应)。

您还应该使用像 @Column(nullable = false) 这样的 JPA 注释来为 jpa 提供程序提供提示,以生成正确的 DDL,以创建具有所需数据库约束的表列。如果您可以或想要依赖像 Hibernate 这样的 JPA 提供程序,它默认将 bean 验证约束应用于 DDL,那么您可以省略它们。


V
Vlad Mihalcea

JPA @Column 注释

@Column 注释的 nullable 属性有两个用途:

它由模式生成工具使用

它由 Hibernate 在刷新持久性上下文期间使用

模式生成工具

HBM2DDL 架构生成工具在生成 CREATE TABLE 语句时将 @Column(nullable = false) 实体属性转换为关联表列的 NOT NULL 约束。

正如我在 Hibernate 用户指南中解释的那样,最好使用像 Flyway 这样的工具,而不是依赖 HBM2DDL 机制来生成数据库模式。

持久性上下文刷新

在刷新 Persistence Context 时,Hibernate ORM 还使用 @Column(nullable = false) 实体属性:

new Nullability( session ).checkNullability( values, persister, true );

如果验证失败,Hibernate 会抛出一个 PropertyValueException,并阻止 INSERT 或 UPDATE 语句被执行:

if ( !nullability[i] && value == null ) {
    //check basic level one nullablilty
    throw new PropertyValueException(
            "not-null property references a null or transient value",
            persister.getEntityName(),
            persister.getPropertyNames()[i]
        );    
}

Bean 验证 @NotNull 注解

@NotNull 注释由 Bean Validation 定义,就像 Hibernate ORM 是最流行的 JPA 实现一样,最流行的 Bean Validation 实现是 Hibernate Validator 框架。

将 Hibernate Validator 与 Hibernate ORM 一起使用时,Hibernate Validator 将在验证实体时抛出 ConstraintViolation


你为什么说flyway比生成模式更好?
这是一个很好的观察。我用参考链接更新了答案。
感谢您的参考和很好的答案!
感谢您的出色回答。如果我不想使用架构生成工具或者 @NotNull 就足够了,我应该两者兼有吗? @Basic(optional=false) 是否与 @Column(nullable = false) 相同?
我从未在我从事的任何项目中使用过 @NotNull。我认为我没有使用过 @Basic(optional=false)。我不确定 Hibernate 是否使用那个。我仅在生成架构时使用 @Column(nullable = false)。总而言之,使用 FlywayDB 定义您的数据库架构,并在每一层上进行验证:Web、控制器、服务层。
A
Aleksandar Radulović

有趣的是,所有来源都强调 @Column(nullable=false) 仅用于 DDL 生成。

然而,即使没有 @NotNull 注解,并且 hibernate.check_nullability 选项设置为 true,Hibernate 也会对要持久化的实体进行验证。

如果 nullable=false 属性没有值,它将抛出 PropertyValueException 说“非空属性引用空值或瞬态值”,即使在数据库层中没有实现此类限制。

此处提供有关 hibernate.check_nullability 选项的更多信息:http://docs.jboss.org/hibernate/orm/5.0/userguide/html_single/Hibernate_User_Guide.html#configurations-mapping