Spring DataIntegrityViolationException

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.

I usually post about Spring stuff on Google+ - you can follow me there:

 

Get My 3 Spring eBooks
There’s no “one single way” to build an app. This is one way that I found works well.
×
Build Your Web App with Spring (and quickly prototype it to 90%)

,

  • http://agung-setiawan.com/ Agung Setiawan

    perfect!
    exactly what i’m looking
    thank you brother :-)

  • Sergio

    How do you manage that and in particular to send messages to the UI? I have seen this: http://stackoverflow.com/questions/9842672/best-practise-propagating-unique-violation-exceptions-to-ui but it’s not clear how it forward the error messages to the UI? I understood that all the error messages are into the BindingResults object and through I can pass the different messages but I don’t know in this case how I could solve it. Thank you very much for your article!

    • http://www.baeldung.com/ Eugen Paraschiv

      Hey Sergio – passing error/validation messages to the UI is a non-trivial problem, and it depends a lot on what kinds of app you’re working with. For example, for a REST API, you can check out my article here. For a more validation focused article, you can also look at Petri’s post here. Hope that will help you get on the right track.
      Cheers,
      Eugen.