Spring DataIntegrityViolationException – Spring DataIntegrityViolationException

最后修改: 2013年 5月 17日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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.

在这篇文章中,我们将讨论Spring org.springframework.dao.DataIntegrityViolationException – 这是一个通用的数据异常,通常由Spring异常转换机制在处理低级别的持久性异常时抛出。这篇文章将讨论这种异常最常见的原因,以及每个原因的解决方案。

2. DataIntegrityViolationException and Spring Exception Translation

2.DataIntegrityViolationException和Spring Exception翻译

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:

Spring的异常翻译机制可以透明地应用于所有用@Repository注释的Bean–通过在Context中定义一个异常翻译Bean后处理器Bean。

<bean id="persistenceExceptionTranslationPostProcessor" 
   class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

Or in Java:

或者在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.

在Spring中可用的较早的持久化模板–HibernateTemplate、JpaTemplate等,也默认启用了Exception翻译机制。

3. Where Is DataIntegrityViolationException Thrown

3.在哪里抛出DataIntegrityViolationException

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.

当Spring与Hibernate配置在一起时,异常会在Spring提供的异常转换层中抛出 – SessionFactoryUtils – convertHibernateAccessException

There are three possible Hibernate exceptions that may cause the DataIntegrityViolationException to be thrown:

有三种可能的Hibernate异常会导致抛出DataIntegrityViolationException

  • 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.

当Spring被配置为JPA作为其持久化提供者时,DataIntegrityViolationException被抛出,与Hibernate类似,在异常转换层–即在EntityManagerFactoryUtils – convertJpaAccessExceptionIfPossible

There is a single JPA exception that may trigger a DataIntegrityViolationException to be thrown – the javax.persistence.EntityExistsException.

有一个JPA异常可能引发DataIntegrityViolationException被抛出–javax.persistence.EntityExistsException

4. Cause: org.hibernate.exception.ConstraintViolationException

4.原因 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.

这是迄今为止最常见的抛出DataIntegrityViolationException的原因–Hibernate的ConstraintViolationException表明操作违反了数据库完整性约束。

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:

考虑下面的例子–对于通过ParentChild实体之间的显式外键列的一对一映射,以下操作应该失败。

@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:

Parent实体对Child实体有一个外键–所以删除孩子会破坏Parent上的外键约束–这会导致ConstraintViolationException–被Spring包装成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:

为了解决这个问题,应该先删除Parent

@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

5.原因 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.

这是导致DataIntegrityViolationException的一个比较常见的原因–在Hibernate中,这将归结为一个实体被持久化的问题。要么实体有一个被定义为not-null约束的空属性,要么实体的关联可能引用了一个未保存的、暂时的实例

For example, the following entity has a not-null name property –

例如,以下实体有一个非空的name属性 –

@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:

如果下面的测试试图用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:

一个数据库集成约束被违反,因此抛出了DataIntegrityViolationException

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

6.原因 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:

Hibernate DataException 表示一个无效的SQL语句–在那个特定的环境中,语句或数据出了问题。例如,使用之前的Foo实体,下面的内容会触发这个异常。

@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:

用长的name值持久化对象的实际异常是。

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

7.原因 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.

与Hibernate类似,EntityExistsException JPA异常也会被Spring异常翻译包装成DataIntegrityViolationException。唯一不同的是,JPA本身已经是高水平的,这使得这个JPA异常成为数据完整性违规的唯一潜在原因。

8. Potentially DataIntegrityViolationException

8.潜在的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.

在某些情况下,DataIntegrityViolationException可能被预期,另一个异常可能被抛出–其中一个情况是如果JSR-303验证器,例如hibernate-validator 4或5存在于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:

在这种情况下,如果下面的实体以name的空值被持久化,它将不再因持久化层触发的数据完整性违反而失败。

@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失败。

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

9.结论

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.

在本文结束时,我们应该有一张清晰的地图来浏览可能导致Spring中出现DataIntegrityViolationException的各种原因和问题,并很好地掌握了如何修复所有这些问题。

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.

所有异常的实现都可以在github项目中找到 – 这是一个基于Eclipse的项目,所以应该很容易导入并按原样运行。