1. Overview
In this article, we will discuss the Spring org.springframework.dao.DataIntegrityViolationException – this is a generic data exception typically thrown by the Spring exception translation mechanism when dealing with lower level persistence exceptions. The article will discuss the most common causes of this exception along with the solution for each one.
2. DataIntegrityViolationException and Spring Exception Translation
The Spring exception translation mechanism can be applied transparently to all beans annotated with @Repository – by defining an exception translation bean post processor bean in the Context:
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Or in Java:
@Configuration
public class PersistenceHibernateConfig{
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
The Exception translation mechanism is also enabled by default on the older persistence template available in Spring – the HibernateTemplate, JpaTemplate, etc.
3. Where Is DataIntegrityViolationException Thrown
3.1. DataIntegrityViolationException with Hibernate
When Spring is configured with Hibernate, the exception is thrown in the exception translation layer provided by Spring – SessionFactoryUtils – convertHibernateAccessException.
There are three possible Hibernate exceptions that may cause the DataIntegrityViolationException to be thrown:
- org.hibernate.exception.ConstraintViolationException
- org.hibernate.PropertyValueException
- org.hibernate.exception.DataException
3.2. DataIntegrityViolationException With JPA
When Spring is configured with JPA as its persistence provider, the DataIntegrityViolationException is thrown, similar to Hibernate, in the exception translation layer – namely in EntityManagerFactoryUtils – convertJpaAccessExceptionIfPossible.
There is a single JPA exception that may trigger a DataIntegrityViolationException to be thrown – the javax.persistence.EntityExistsException.
4. Cause: org.hibernate.exception.ConstraintViolationException
This is by far the most common cause of DataIntegrityViolationException being thrown – the Hibernate ConstraintViolationException indicates that the operation has violated a database integrity constraint.
Consider the following example – for One to One mapping through an explicit foreign key column between a Parent and Child entities – the following operations should fail:
@Test(expected = DataIntegrityViolationException.class)
public void whenChildIsDeletedWhileParentStillHasForeignKeyToIt_thenDataException() {
Child childEntity = new Child();
childService.create(childEntity);
Parent parentEntity = new Parent(childEntity);
service.create(parentEntity);
childService.delete(childEntity);
}
The Parent entity has a foreign key to the Child entity – so deleting the child would break the foreign key constraint on the Parent – which results in a ConstraintViolationException – wrapped by Spring in the DataIntegrityViolationException:
org.springframework.dao.DataIntegrityViolationException:
could not execute statement; SQL [n/a]; constraint [null];
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at o.s.orm.h.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:138)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
To solve this, the Parent should be deleted first:
@Test
public void whenChildIsDeletedAfterTheParent_thenNoExceptions() {
Child childEntity = new Child();
childService.create(childEntity);
Parent parentEntity = new Parent(childEntity);
service.create(parentEntity);
service.delete(parentEntity);
childService.delete(childEntity);
}
5. Cause: org.hibernate.PropertyValueException
This is one of the more common causes of the DataIntegrityViolationException – in Hibernate, this will come down to an entity being persisted with a problem. Either the entity has a null property which is defined with a not-null constraint, or an association of the entity may reference an unsaved, transient instance.
For example, the following entity has a not-null name property –
@Entity
public class Foo {
...
@Column(nullable = false)
private String name;
...
}
If the following test tries to persist the entity with a null value for name:
@Test(expected = DataIntegrityViolationException.class)
public void whenInvalidEntityIsCreated_thenDataException() {
fooService.create(new Foo());
}
A database integrigy constraint is violated, and so the DataIntegrityViolationException is thrown:
org.springframework.dao.DataIntegrityViolationException:
not-null property references a null or transient value:
org.baeldung.spring.persistence.model.Foo.name;
nested exception is org.hibernate.PropertyValueException:
not-null property references a null or transient value:
org.baeldung.spring.persistence.model.Foo.name
at o.s.orm.h.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:160)
...
Caused by: org.hibernate.PropertyValueException:
not-null property references a null or transient value:
org.baeldung.spring.persistence.model.Foo.name
at o.h.e.i.Nullability.checkNullability(Nullability.java:103)
...
6. Cause: org.hibernate.exception.DataException
A Hibernate DataException indicates an invalid SQL Statement – something was wrong with the statement or the data, in that particular context. For example, using or Foo entity from before, the following would trigger this exception:
@Test(expected = DataIntegrityViolationException.class)
public final void whenEntityWithLongNameIsCreated_thenDataException() {
service.create(new Foo(randomAlphabetic(2048)));
}
The actual exception for persisting the object with a long name value is:
org.springframework.dao.DataIntegrityViolationException:
could not execute statement; SQL [n/a];
nested exception is org.hibernate.exception.DataException: could not execute statement
at o.s.o.h.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:143)
...
Caused by: org.hibernate.exception.DataException: could not execute statement
at o.h.e.i.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:71)
In this particular example, the solution is to specify the max length of the name:
@Column(nullable = false, length = 4096)
7. Cause: javax.persistence.EntityExistsException
Simillarly to Hibernate, the EntityExistsException JPA exception will also be wrapped by the Spring Exception Translation into a DataIntegrityViolationException. The only difference is that JPA itself is already high level which makes this JPA exception the only potential cause of data integrity violations.
8. Potentially DataIntegrityViolationException
In some cases where the DataIntegrityViolationException may be expected, another exception may be thrown – one such case is if a JSR-303 validator, such as hibernate-validator 4 or 5 exists on the classpath.
In that case, if the following entity is persisted with a null value for name, it will no longer fail with a data integrity violation triggered by the persistence layer:
@Entity
public class Foo {
...
@Column(nullable = false)
@NotNull
private String name;
...
}
This is because the execution won't get to the persistence layer – it will fail before that with a javax.validation.ConstraintViolationException:
javax.validation.ConstraintViolationException:
Validation failed for classes [org.baeldung.spring.persistence.model.Foo]
during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[ ConstraintViolationImpl{
interpolatedMessage='may not be null', propertyPath=name,
rootBeanClass=class org.baeldung.spring.persistence.model.Foo,
messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
at o.h.c.b.BeanValidationEventListener.validate(BeanValidationEventListener.java:159)
at o.h.c.b.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:94)
9. Conclusions
At the end of this article, we should have a clear map to navigate the variety of causes and problems that may lead to a DataIntegrityViolationException in Spring, as well as a good grasp on how to fix all of these problems.
The implementation of all exceptions examples can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.