【问题标题】:Confusion: @NotNull vs. @Column(nullable = false) with JPA and Hibernate混淆:@NotNull 与 @Column(nullable = false) 与 JPA 和 Hibernate
【发布时间】:2011-11-18 08:44:38
【问题描述】:
  1. 当它们出现在@Entity 的字段/getter 上时,它们之间有什么区别? (我通过 Hibernate 持久化实体)。

  2. 它们各自属于什么框架和/或规范?

  3. @NotNull 位于javax.validation.constraints 内。在javax.validation.constraints.NotNull javadoc 中它说

    注解的元素不能为空

    但它并没有说明元素在数据库中的表示,那我为什么要在列中添加约束nullable=false

【问题讨论】:

    标签: java hibernate jpa persistence hibernate-annotations


    【解决方案1】:

    @NotNull 是一个JSR 303 Bean Validation 注释。它与数据库约束本身无关。然而,由于 Hibernate 是 JSR 303 的参考实现,它智能地获取这些约束并将它们转换为您的数据库约束,因此您以一个的价格获得两个。 @Column(nullable = false) 是 JPA 将列声明为非空的方式。 IE。前者用于验证,后者用于指示数据库模式详细信息。您只是从 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 在您不知道的后续评论中提出的内容中是有效的。
    【解决方案2】:

    最新版本的休眠 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,那么您可以省略它们。

    【讨论】:

      【解决方案3】:

      JPA @Column 注释

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

      • 模式生成工具使用它
      • Hibernate 在刷新持久性上下文期间使用它

      架构生成工具

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

      正如我在Hibernate User Guide 中解释的那样,最好使用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、控制器、服务层。
      【解决方案4】:

      有趣的是,所有消息来源都强调@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

      【讨论】:

        猜你喜欢
        • 2011-02-23
        • 1970-01-01
        • 2014-09-11
        • 2011-03-20
        • 1970-01-01
        • 2019-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多