Hibernate handling of nullable=true in #Column - java

I am using Hibernate with Springs backed by a Mysql db.
Here is the entity similar to the one i use to make an entry
#Entity
#Table(name = "my_table") {
#Basic
#Column(name = "my_string", nullable = false)
private String myString;
}
The sql definition is
CREATE TABLE `my_table` (
`my_string` varchar(200) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Though the table allows null values, the column myString is non-nullable as per the JPA annotation. This is leading to unpredictable behaviour.
Q: Is the non-nullable ALWAYS enforced at the entity level while making inserts? Or is there some case in which it may be ignored
My expectation was that all of the entries should have been rejected. But with this setup, many entries (>7000) have gone into the table.
Only sometimes i get a DataIntegrityViolation exception from spring
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: ...; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: ....
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:652)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
....
....
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: ....
at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:103)
....
I understand that having separate signature in the entity and the table is a bad practice, But i'm trying to identify what causes this behaviour and any other loopholes that might have been left out due to it.
Versions -
Mysql- 5.5
Hibernate - 4.0.0
Hibernate-jpa - 2.0
Spring-core- 3.1.0
Spring-jdbc- 3.1.2

People frequently confuse the #Column(nullable) and #NotNull annotations.
The #Column(nullable) is meant for the generated DDL scripts. But you don't use Hibernate to generate your DDL, so you shouldn't rely on it at all. What you want is #NotNull which is a runtime validation trigger.
If you define the Hibernate Validator Annotation (or JPA 2.0 ones) you can get the DDL for those as well:
Out of the box, Hibernate (as of version 3.5.x) will translate the
constraints you have defined for your entities into mapping metadata.
For example, if a property of your entity is annotated #NotNull, its
columns will be declared as not null in the DDL schema generated by
Hibernate.
And make sure you enable validation if you're using JPA with Hibernate.
If you are using JPA 2 and Hibernate Validator is in the classpath the
JPA2 specification requires that Bean Validation gets enabled. The
properties javax.persistence.validation.group.pre-persist,
javax.persistence.validation.group.pre-update and
javax.persistence.validation.group.pre-remove as described in Section
10.1.2, “Hibernate event-based validation” can in this case be configured in persistence.xml. persistence.xml also defines a node
validation-mode which can be set to AUTO, CALLBACK, NONE. The default
is AUTO.

Related

HIbernate suddenly started to validate JPA annotations

I have an entity that maps a database table in my code, this entity has the following attribute:
#Column(name = "CARD_TYPE", length = 255,nullable = false)
private String cardType;
When this entity was created the column in the database had this field defined as non nullable, but due to a change in the business logic it is no longer the case. The field in the database was updated to allow this field to be null but the entity in the java code was not. Now, when testing in several environments with different instances of the same database we had no problems, but as of yesterday, after this code had been running for about a week without issues, we are getting this message over and over
error javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: entity.cardType | Cause: org.hibernate.PropertyValueException: not-null property references a null or transient value: entity.cardType
This exception if from Hibernate which means that it never even tries to reach the database. Is my understanding that #Column annotation is only used when creating the database schemas from code and not used for validation. We have another instance of the same code in another server running against the same database and it doesn't show the error.

Springboot 2 CrudRepository.save always throws ConstraintViolationException

I have Migrated the Springboot version from 1.4.3.RELEASE to 2.1.0.RELEASE in my project. After that CrudRepository.save() always throws org.hibernate.exception.ConstraintViolationException: could not execute statement.
This is what I can see in the Logs :
o.h.e.j.s.SqlExceptionHelper[m: SQL Error: 1062, SQLState: 23000
o.h.e.j.s.SqlExceptionHelper[m: Duplicate entry '11' for key 'PRIMARY'
o.h.i.ExceptionMapperStandardImpl[m: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement
This is the entity I am trying to save.
#Getter
#Setter
#Entity
#Table(name = "project_m")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name" , nullable = false)
private String name;
//other fields
}
What has changed from Springboot 1.4.3.RELEASE to 2.1.0.RELEASE is the internal Hibernate version from 5.0 to 5.3.
And what has changed in this is the way the SequenceGenerator works, which is used in case the strategy is GenerationType.AUTO (as is in your case).
Link to hibernate migration doc here.
More details on hibernate generation strategy here.
My guess is there are 2 parallel sessions inserting into this table, and both of them now share a local copy of the sequence number, which creates this collision. Not sure though!
My suggestion would be to change the strategy to GenerationType.SEQUENCE and try.
ConstraintViolationException occurred due to the fact that your primary key constraint for SQL database violates
In SQL the primary key is a unique key to identify the record, the database will throw an exception when you trying to insert a duplicate value to a primary column.
which in turn got by the hibernate and passed to your code and is the reason for this exception.
From Springboot 1.4.3.RELEASE to 2.1.0.RELEASE Hibernate version is updated from 5.0 to 5.3.
The way Hibernate interprets AUTO generation type has changed starting with Hibernate version 5.0
If you use strategy="AUTO", Hibernate will generate a table called hibernate_sequence to provide the next number for the ID sequence. You may have forgotten to add the AutoIncrement feature to your table's PK.
Another way to fix is use following annotations with strategy="AUTO"
#Id
#GeneratedValue(
strategy= GenerationType.AUTO,
generator="native"
)
#GenericGenerator(
name = "native",
strategy = "native"
)
private Long id;
You may use generation strategy strategy="IDENTITY" to enforce using the AutoIncrement feature available in SQL and avoid creating a table.
Pls check here to get some more insights
I got a workaround for this issue by setting a large value in hibernate_sequence table. I saw that the primary key value from the duplicate primary key error is generated from a table named hibernate_sequence.
When we set GenerationType.AUTO in the entity,Hibernate selects the generation strategy based on the Hibernate dialect. In older versions , Hibernate selected the GenerationType.IDENTITY as default for MySQL databases.
It now selects the GenerationType.TABLE which uses a database table to generate primary keys

Hibernate null constraint violation on #Id with #GeneratedValue

I am using Hibernate 4.1.3 (JPA) on the Play! framework. The database is PostgreSQL 8.4.2. The schema was generated using hibernate.hbm2ddl.auto="update".
Short version: I have a class that has an #Id field that is a #GeneratedValue. Sometimes, when persisting it, I get a null-column violation, why?
More details:
I have a really simple class that I want to save to the database, that looks like this:
#Entity
class MyObject {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#NotNull
public String email;
public Integer total;
}
I usually create an instance of MyObject, I assign a value to email and total fields while id is null and I save it via EntityManager.persist(). Hibernate gets an id for the new object and saves it to the DB.
However sometimes, I get the following stacktrace:
2012-05-19 00:45:16,335 - [ERROR] - from org.hibernate.engine.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:144] in play-akka.actor.actions-dispatcher-6
ERROR: null value in column "id" violates not-null constraint
2012-05-19 00:45:16,350 - [ERROR] - from application in play-akka.actor.actions-dispatcher-6
! #6ad7j3p8p - Internal server error, for request [POST /method] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: null value in column "id" violates not-null constraint]]
How is this possible? How can I track down the problem?
Here's the relevant DDL generated by Hibernate:
CREATE TABLE myobject (
id bigint NOT NULL,
email character varying(255) NOT NULL,
physical integer
);
CREATE SEQUENCE hibernate_sequence
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE ONLY dailydetailedscore
ADD CONSTRAINT dailydetailedscore_pkey PRIMARY KEY (id);
Try the annotation #org.hibernate.annotations.GenericGenerator(name = “test-hilo-strategy”, strategy = “hilo”):
#Id
#org.hibernate.annotations.GenericGenerator(name=“hilo-strategy”, strategy = “hilo”)
#GeneratedValue(generator = ”hilo-strategy”)
As someone noted above, AUTO does not do what you think. It uses the underlying DB to determine how to generate values. It may pick sequences (for oracle), identity column (for mssql), or something else that is db specific.
The approach here uses an internal strategy that Hibernate supplies called "hilo".
See chapter 5 of the Hibernate reference manual dealing with "Generator" for a full description of what each of the supplied ones does.
Neither the OP solution nor Matt's solution worked with my PostgreSQL 9.3.
But this one works:
#SequenceGenerator(name="identifier", sequenceName="mytable_id_seq", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="identifier")
Replace mytable_id_seq with the name of the sequence that generates your id.
Use Hibernate method:- save(String entityName, Object object)
Persist the given transient instance, first assigning a generated identifier.
Do not use :- #GeneratedValue(strategy=GenerationType.IDENTITY) for primary key if you want to persist user define Id.
For detail:-
http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Session.html#save(java.lang.String
In mycase i was using Identity generation strategy and i have set the wrong data type in Postgres. Following steps i performed to debug the problem.
set
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true in application.properties and Drop the tables.
By this hibernate will automatically create the schema for you on the basis of your data-type.I noticed change in the datatype of id field.
Now when i tried any post requests, everything worked fine.

Writing comments for an entity bean property in hibernate

Is it possible to write comments for every property of an Entity bean in Hibernate, such that when i generate the table using ddl, it creates the tables with column comments?
I think you have to use the columnDefinition property of the #Column annotation. See http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Web_Server/1.0/html-single/Hibernate_Annotations_Reference_Guide/index.html
or EJB3 reference (ejb-3_0-fr-spec-persistence.pdf -- page 167):
http://download.oracle.com/otndocs/jcp/ejb-3_0-fr-eval-oth-JSpec/

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?
#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.
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.
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.
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.

Categories

Resources