ChatGPT解决这个技术问题 Extra ChatGPT

Confusion: @NotNull vs. @Column(nullable = false) with JPA and Hibernate

When they appear on a field/getter of an @Entity, what is the difference between them? (I persist the Entity through Hibernate). What framework and/or specification each one of them belongs to? @NotNull is located within javax.validation.constraints. In the javax.validation.constraints.NotNull javadoc it says The annotated element must not be null but it does not speak of the element's representation in the database, so why would I add the constraint nullable=false to the column?


C
Chakkakuru

@NotNull is a JSR 303 Bean Validation annotation. It has nothing to do with database constraints itself. As Hibernate is the reference implementation of JSR 303, however, it intelligently picks up on these constraints and translates them into database constraints for you, so you get two for the price of one. @Column(nullable = false) is the JPA way of declaring a column to be not-null. I.e. the former is intended for validation and the latter for indicating database schema details. You're just getting some extra (and welcome!) help from Hibernate on the validation annotations.


Thanks! So if I want my JPA persistence not to be tied to the Hibernate implementation (i.e. change to EJB3) then I have to use both annotations (to prohibit null in both the field and its column)?
I don't know. There's no specification that says a JPA provider must recognize JSR 303 annotations, but that doesn't mean that other providers don't. I can't say whether any does or doesn't.
JPA providers are not required to provide JSR303 implementation but are as per specification required to provide the ability to integrate with any third party JSR303 implementation. So while Hibernate does provide JSR303 you could for whatever reason decide not to use theirs and go with somebody else or use a JPA implementation like openJPA and use somebody else to provide JSR303.Also note Hibernate's JPA implementaion is Also EJB3.It is incorrect to say 'if I want my JPA persistence not to be tied to the Hibernate implementation (i.e. change to EJB3)' JPA is part of EJB3 specification.
@Shahzeb: The question isn't about who supports/provides JSR 303 validation. It's about which ORM(s) recognize JSR 303 annotations like @NotNull, @Size, @Min, @Max, etc., and translate those into database constraints.
Yes but my comment is valid in the context of what OP asked in the subsequent comment which you did not know.
K
Kalle Richter

The most recent versions of hibernate JPA provider applies the bean validation constraints (JSR 303) like @NotNull to DDL by default (thanks to hibernate.validator.apply_to_ddl property defaults to true). But there is no guarantee that other JPA providers do or even have the ability to do that.

You should use bean validation annotations like @NotNull to ensure, that bean properties are set to a none-null value, when validating java beans in the JVM (this has nothing to do with database constraints, but in most situations should correspond to them).

You should additionally use the JPA annotation like @Column(nullable = false) to give the jpa provider hints to generate the right DDL for creating table columns with the database constraints you want. If you can or want to rely on a JPA provider like Hibernate, which applies the bean validation constraints to DDL by default, then you can omit them.


V
Vlad Mihalcea

The JPA @Column Annotation

The nullable attribute of the @Column annotation has two purposes:

it's used by the schema generation tool

it's used by Hibernate during flushing the Persistence Context

Schema Generation Tool

The HBM2DDL schema generation tool translates the @Column(nullable = false) entity attribute to a NOT NULL constraint for the associated table column when generating the CREATE TABLE statement.

As I explained in the Hibernate User Guide, it's better to use a tool like Flyway instead of relying on the HBM2DDL mechanism for generating the database schema.

Persistence Context Flush

When flushing the Persistence Context, Hibernate ORM also uses the @Column(nullable = false) entity attribute:

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

If the validation fails, Hibernate will throw a PropertyValueException, and prevents the INSERT or UPDATE statement to be executed needesly:

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]
        );    
}

The Bean Validation @NotNull Annotation

The @NotNull annotation is defined by Bean Validation and, just like Hibernate ORM is the most popular JPA implementation, the most popular Bean Validation implementation is the Hibernate Validator framework.

When using Hibernate Validator along with Hibernate ORM, Hibernate Validator will throw a ConstraintViolation when validating the entity.


Why do you state that flyway is better than generating schema?
That's a good observation. I updated the answer with a reference link.
Thanks for the reference and great answer!
Thanks for the great answer. Should i have both if i don't want to use schema generation tool or @NotNull is enough? and is @Basic(optional=false) the same as @Column(nullable = false)?
I never used @NotNull on any project I worked on. I don't think I've used @Basic(optional=false). I'm not sure if Hibernate uses that one. I used @Column(nullable = false) only when the schema was generated. All in all, define your DB schema using FlywayDB, and validate on every layer: web, controller, service layer.
A
Aleksandar Radulović

Interesting to note, all sources emphasize that @Column(nullable=false) is used only for DDL generation.

However, even if there is no @NotNull annotation, and hibernate.check_nullability option is set to true, Hibernate will perform validation of entities to be persisted.

It will throw PropertyValueException saying that "not-null property references a null or transient value", if nullable=false attributes do not have values, even if such restrictions are not implemented in the database layer.

More information about hibernate.check_nullability option is available here: http://docs.jboss.org/hibernate/orm/5.0/userguide/html_single/Hibernate_User_Guide.html#configurations-mapping.