Рубрики
Без рубрики

Весеннее исключение DataIntegrityViolationException

Spring DataIntegrityViolationException – Причины и решения для Hibernate и JPA: ConstraintViolationException, PropertyValueException, DataException, EntityExistsException.

Автор оригинала: Eugen Paraschiv.

1. Обзор

В этой статье мы обсудим исключение Spring org.springframework.dao.DataIntegrityViolationException – это общее исключение данных, обычно создаваемое механизмом трансляции исключений Spring при работе с исключениями сохранения более низкого уровня. В статье будут рассмотрены наиболее распространенные причины этого исключения, а также решение для каждого из них.

Дальнейшее чтение:

Поддержка Spring Data Java 8

Аннотации весенних данных

Работа с отношениями в Spring Data REST

2. Исключение DataIntegrityViolationException и перевод исключения Spring

Механизм трансляции исключений Spring может быть прозрачно применен ко всем компонентам, аннотированным с помощью @Repository – путем определения компонента преобразования исключений в контексте:

Или на Java:

@Configuration
public class PersistenceHibernateConfig{
   @Bean
   public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
      return new PersistenceExceptionTranslationPostProcessor();
   }
}

Механизм трансляции исключений также включен по умолчанию в более старом шаблоне сохранения, доступном весной, – HibernateTemplate, JpaTemplate и т. Д.

3. Где Выбрасывается исключение DataIntegrityViolationException

3.1. Исключение DataIntegrityViolationException с гибернацией

Когда Spring настроен с помощью Hibernate, исключение генерируется в слое трансляции исключений, предоставляемом Spring – SessionFactoryUtils – convertHibernateAccessException .

Существует три возможных исключения спящего режима, которые могут вызвать исключение DataIntegrityViolationException :

  • Существует три возможных исключения спящего режима, которые могут вызвать исключение
  • DataIntegrityViolationException
  • :

3.2. Исключение DataIntegrityViolationException С JPA

Когда Spring настроен с JPA в качестве поставщика персистентности, исключение DataIntegrityViolationException генерируется, аналогично Hibernate, на уровне трансляции исключений, а именно в EntityManagerFactoryUtils – convertJpaAccessExceptionIfPossible .

Существует единственное исключение JPA, которое может вызвать исключение DataIntegrityViolationException , которое будет вызвано – javax.persistence.Исключение EntityExistsException .

4. Причина: org.hibernate.exception.Исключение ConstraintViolationException

Это, безусловно, самая распространенная причина возникновения исключения DataIntegrityViolationException – исключение Hibernate ConstraintViolationException указывает на то, что операция нарушила ограничение целостности базы данных.

Рассмотрим следующий пример – для сопоставления Один к одному через явный столбец внешнего ключа между сущностями Parent и Child – следующие операции должны завершиться неудачно:

@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);
}

Сущность Parent имеет внешний ключ к сущности Child – поэтому удаление дочернего элемента нарушит ограничение внешнего ключа для родителя, что приведет к исключению 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

Чтобы решить эту проблему, сначала следует удалить 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. Причина: орг.спящий режим.Исключение PropertyValueException

Это одна из наиболее распространенных причин исключения DataIntegrityViolationException – в режиме гибернации это приведет к тому, что объект будет сохраняться с проблемой. Либо сущность имеет свойство null , которое определено с помощью ограничения not-null , либо ассоциация сущности может ссылаться на несохраненный, временный экземпляр .

Например, следующая сущность имеет свойство not-null name

@Entity
public class Foo {
   ...

   @Column(nullable = false)
   private String name;

   ...
}

Если следующий тест попытается сохранить сущность с нулевым значением для name :

@Test(expected = DataIntegrityViolationException.class)
public void whenInvalidEntityIsCreated_thenDataException() {
   fooService.create(new Foo());
}

Нарушается ограничение целостности базы данных, и поэтому возникает исключение 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. Причина: org.hibernate.exception.Исключение данных

Исключение Hibernate DataException указывает на недопустимую инструкцию SQL – что-то было не так с инструкцией или данными в этом конкретном контексте. Например, при использовании или Foo entity из предыдущего, следующее вызовет это исключение:

@Test(expected = DataIntegrityViolationException.class)
public final void whenEntityWithLongNameIsCreated_thenDataException() {
   service.create(new Foo(randomAlphabetic(2048)));
}

Фактическим исключением для сохранения объекта с длинным именем значением является:

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)

В этом конкретном примере решение состоит в том, чтобы указать максимальную длину имени:

@Column(nullable = false, length = 4096)

7. Причина: javax.настойчивость.Исключение EntityExistsException

Аналогично Hibernate, исключение EntityExistsException JPA также будет обернуто переводом исключения Spring в исключение DataIntegrityViolationException . Единственная разница заключается в том, что сам JPA уже находится на высоком уровне, что делает это исключение JPA единственной потенциальной причиной нарушения целостности данных.

8. Потенциально DataIntegrityViolationException

В некоторых случаях, когда может ожидаться исключение DataIntegrityViolationException , может возникнуть другое исключение – один из таких случаев, если в пути к классу существует валидатор JSR-303, такой как hibernate-validator 4 или 5.

В этом случае, если следующая сущность сохраняется с нулевым значением для name , она больше не будет терпеть неудачу с нарушением целостности данных , вызванным уровнем сохранения:

@Entity
public class Foo {
    ...
    @Column(nullable = false)
    @NotNull
    private String name;

    ...
}

Это происходит потому, что выполнение не попадет на уровень сохраняемости – до этого оно завершится неудачей с помощью 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. Выводы

В конце этой статьи у нас должна быть четкая карта для навигации по множеству причин и проблем, которые могут привести к DataIntegrityViolationException весной, а также хорошее представление о том, как исправить все эти проблемы.

Примеры реализации всех исключений можно найти в проекте github – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.