Spring DataIntegrityViolationException

1. Ikhtisar

Dalam artikel ini, kita akan membahas Spring org.springframework.dao.DataIntegrityViolationException - ini adalah pengecualian data umum yang biasanya dilemparkan oleh mekanisme terjemahan pengecualian Spring saat menangani pengecualian persistensi tingkat yang lebih rendah. Artikel ini akan membahas penyebab paling umum dari pengecualian ini bersama dengan solusi untuk masing-masing penyebab.

2. Terjemahan DataIntegrityViolationException dan Spring Exception

Mekanisme penerjemahan pengecualian Musim Semi dapat diterapkan secara transparan ke semua kacang yang dianotasi dengan @Repository - dengan mendefinisikan sebuah kacang pengolah pos kacang terjemahan pengecualian dalam Konteks:

Atau di Jawa:

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

Mekanisme terjemahan Exception juga diaktifkan secara default pada template persistensi lama yang tersedia di Spring - HibernateTemplate, JpaTemplate, dll.

3. Di mana DataIntegrityViolationException Dilempar

3.1. DataIntegrityViolationException dengan Hibernate

Ketika Spring dikonfigurasi dengan Hibernate, pengecualian dilemparkan ke lapisan terjemahan pengecualian yang disediakan oleh Spring - SessionFactoryUtils - convertHibernateAccessException .

Ada tiga kemungkinan pengecualian Hibernate yang dapat menyebabkan DataIntegrityViolationException dilemparkan:

  • org.hibernate.exception.ConstraintViolationException
  • org.hibernate.PropertyValueException
  • org.hibernate.exception.DataException

3.2. DataIntegrityViolationException Dengan JPA

Ketika Spring dikonfigurasi dengan JPA sebagai penyedia persistensi, DataIntegrityViolationException dilempar, mirip dengan Hibernate, di lapisan terjemahan pengecualian - yaitu di EntityManagerFactoryUtils - convertJpaAccessExceptionIfPossible .

Ada satu pengecualian JPA yang dapat memicu pelemparan DataIntegrityViolationException - javax.persistence.EntityExistsException .

4. Penyebab: org.hibernate.exception.ConstraintViolationException

Sejauh ini, ini adalah penyebab paling umum DataIntegrityViolationException dilempar - Hibernate ConstraintViolationException menunjukkan bahwa operasi telah melanggar batasan integritas database.

Pertimbangkan contoh berikut - untuk pemetaan One to One melalui kolom kunci asing eksplisit antara entitas Induk dan Anak - operasi berikut akan gagal:

@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 entitas memiliki kunci asing ke Anak entitas - sehingga menghapus anak akan memecahkan kendala asing kunci pada Orang Tua - yang hasil dalam ConstraintViolationException - dibungkus oleh musim semi di 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

Untuk mengatasi ini, Induk harus dihapus terlebih dahulu:

@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. Penyebab: org.hibernate.PropertyValueException

Ini adalah salah satu penyebab yang lebih umum dari DataIntegrityViolationException - dalam Hibernate, ini akan menjadi penyebab entitas bertahan dengan masalah. Entah entitas tersebut memiliki properti null yang ditentukan dengan batasan bukan null , atau asosiasi entitas dapat merujuk pada instance transien yang tidak disimpan .

Misalnya, entitas berikut memiliki properti nama bukan-null -

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

Jika pengujian berikut mencoba untuk mempertahankan entitas dengan nilai null untuk nama :

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

Batasan integrigy database dilanggar, sehingga DataIntegrityViolationException muncul :

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. Penyebab: org.hibernate.exception.DataException

Hibernate DataException menunjukkan Pernyataan SQL yang tidak valid - ada yang salah dengan pernyataan atau datanya, dalam konteks tertentu itu. Misalnya, menggunakan entitas atau Foo dari sebelumnya, berikut ini akan memicu pengecualian ini:

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

Pengecualian sebenarnya untuk mempertahankan objek dengan nilai nama panjang adalah:

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)

Dalam contoh khusus ini, solusinya adalah menentukan panjang maksimal nama:

@Column(nullable = false, length = 4096)

7. Penyebab: javax.persistence.EntityExistsException

Mirip dengan Hibernate, pengecualian JPA EntityExistsException juga akan dibungkus oleh Spring Exception Translation ke dalam DataIntegrityViolationException . Satu-satunya perbedaan adalah JPA sendiri sudah berada pada level tinggi yang membuat pengecualian JPA ini menjadi satu-satunya penyebab potensial pelanggaran integritas data.

8. Berpotensi DataIntegrityViolationException

Dalam beberapa kasus di mana DataIntegrityViolationException mungkin diharapkan, pengecualian lain mungkin dilemparkan - salah satu kasus tersebut adalah jika validator JSR-303, seperti hibernate-validator 4 atau 5 ada di classpath.

Dalam kasus tersebut, jika entitas berikut dipertahankan dengan nilai null untuk nama , itu tidak akan gagal lagi dengan pelanggaran integritas data yang dipicu oleh lapisan persistensi:

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

Ini karena eksekusi tidak akan sampai ke lapisan persistensi - itu akan gagal sebelumnya dengan 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. Kesimpulan

Di akhir artikel ini, kita harus memiliki peta yang jelas untuk menavigasi berbagai penyebab dan masalah yang mungkin mengarah ke DataIntegrityViolationException di Spring, serta pemahaman yang baik tentang cara memperbaiki semua masalah ini.

Penerapan semua contoh pengecualian dapat ditemukan di proyek github - ini adalah proyek berbasis Eclipse, jadi semestinya mudah untuk mengimpor dan menjalankannya apa adanya.