Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

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.

Further reading:

Spring Data Java 8 Support

A quick and practical guide to Java 8 support in Spring Data.

Spring Data Annotations

Learn about the most important annotations we need to handle persistence using the Spring Data project

Working with Relationships in Spring Data REST

A practical guide to working with entity relationships in Spring Data REST.

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.

Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!