混淆:@NotNull 与 @Column(nullable = false) 与 JPA 和 Hibernate
Posted
技术标签:
【中文标题】混淆:@NotNull 与 @Column(nullable = false) 与 JPA 和 Hibernate【英文标题】:Confusion: @NotNull vs. @Column(nullable = false) with JPA and Hibernate 【发布时间】:2011-11-18 08:44:38 【问题描述】:当它们出现在@Entity
的字段/getter 上时,它们之间有什么区别? (我通过 Hibernate 持久化实体)。
它们各自属于什么框架和/或规范?
@NotNull
位于javax.validation.constraints
内。在javax.validation.constraints.NotNull
javadoc 中它说
注解的元素不能为空
但它并没有说明元素在数据库中的表示,那我为什么要在列中添加约束nullable=false
?
【问题讨论】:
【参考方案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
属性有两个用途:
架构生成工具
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。
【讨论】:
以上是关于混淆:@NotNull 与 @Column(nullable = false) 与 JPA 和 Hibernate的主要内容,如果未能解决你的问题,请参考以下文章