Я использую перевод исключений Spring в своем приложении для перевода исключений из базовой структуры ORM (Hibernate), и я обнаружил, что исключения ConstraintViolationException в моих тестовых и производственных средах переводятся по-разному.
В моем отличном модульном тесте у меня есть следующее ...
// provide a non-unique name for a department entity
shouldFail(DataIntegrityViolationException, {
Department d = new Department(name: 'HR')
departmentDao.persist(d)
})
Это работает нормально - ожидаемое исключение DataIntegrityViolationException вызывается из-за базового org.hibernate.exception.ConstraintViolationException . В моем отличном служебном коде у меня есть следующий блок кода, который должен перехватывать то же исключение DataIntegrityViolationException ...
try{
departmentDao.persist(department)
}
// There may be a constraint violation if a department with the same name already exists
catch(DataIntegrityViolationException e){...}
Однако во время выполнения Spring не транслирует исключение, поэтому исключение Hibernate во время выполнения распространяется по стеку.
В трассировке стека упоминается исключение org.springframework.orm.jpa.JpaSystemException, которое, согласно документам, является специфичным для JPA подклассом UncategorizedDataAccessException для системных ошибок JPA, которые не соответствуют ни одному конкретному org.springframework. Дао исключения. " ...
org.hibernate.exception.ConstraintViolationException: не удалось вставить: [com.myapp.Department]; вложенным исключением является javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: не удалось вставить: [com.myapp.Department]
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: не удалось вставить: [com.myapp.Department]; вложенным исключением является javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: не удалось вставить: [com.myapp.Department]
Единственное заметное отличие, которое я вижу, состоит в том, что мой тест поддерживается HSQLDB, а рабочий код - базой данных MsSql. Кто-нибудь может объяснить, почему трансляция исключений отличается в моей среде тестирования и времени выполнения?
Приветствие.
EDIT:
ОК, подробнее ...
И мой контекст тестового приложения, и контекст производственного приложения определяют PersistenceExceptionTranslationPostProcessor следующим образом
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Что касается источника данных, то в тестовом контексте используется источник данных HSQLDB, настроенный в контексте приложения следующим образом
<!-- HSQL-DB memory database; for testing only -->
<bean id="hsqlDs"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:file:target/db/store;shutdown=true" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocation" value="classpath:persistence-test.xml" />
<property name="defaultDataSource" ref="hsqlDs" />
</bean>
<bean id="hsqlEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="store" />
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
</bean>
Контекст prod значительно проще, поскольку он использует источник данных JNDI, определенный в Glassfish, и единицу персистентности, определенную в persistence.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" />
хотя, если я настрою контекст prod для использования LocalEntityManagerFactoryBean, я получу тот же результат.
Похоже, что EntityManagerFactoryUtils вызывается для преобразования исключения, но исключение переводится по-разному в двух средах. Тестовая среда преобразует исключение в org.springframework.dao.DataIntegrityViolationException , но производственная среда преобразует его в org.springframework.orm.jpa.JpaSystemException - см. Трассировку стека производства ниже :
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.Department]; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.Department]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:311)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:369)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy233.persist(Unknown Source)