Преобразование исключений Spring dao ведет себя по-разному в тестировании и производстве - PullRequest
1 голос
/ 09 мая 2011

Я использую перевод исключений 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...