Spring 异常翻译不适用于 JPA

发布于 2024-11-07 22:29:55 字数 14015 浏览 0 评论 0原文

我的 dao 类 com.myapp.dao.hibernate.XyzDaoImpl@Repository 注释

@Repository
public class UserDaoImpl extends GenericDaoJpa implements UserDao {

...
    @Override
    public void saveUser(User user) throws Exception{
        entityManager.persist(user);
    }
...
}

我的 app-data.xml 如下:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
       <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
       <property name="username" value="${db.username}" />
     <property name="password" value="${db.password}" />
     <property name="initialSize" value="5" />
        <property name="maxActive" value="0" />
  </bean>


    <!-- JPA Entity Manager Factory -->
    <bean id="entityManagerFactory"  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
          p:dataSource-ref="dataSource" p:jpaDialect-ref="jpaDialect"
        p:jpaVendorAdapter-ref="jpaVendorAdapter"
    />

    <bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
    </bean>

    <bean name="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"></property>
    </bean>

    <!-- detect les @persistentContext in dao -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


     <!-- This will ensure that hibernate or jpa exceptions are automatically translated into
         Spring's generic DataAccessException hierarchy -->
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>


 <bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />

    <!-- Transaction Config -->
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"
          p:entityManagerFactory-ref="entityManagerFactory"/>

   <context:component-scan base-package="com.myapp.dao.hibernate" />

 <tx:annotation-driven transaction-manager="txManager" />

现在,在我的 jUnit 测试方法中,我故意插入一个重复的对象,然后得到 javax.persistence.PersistenceException 而不是 spring 异常。

@Test public void testSaveUser() {
        String login = "duplicateLogin";

        User user = new User();
        user.setLogin(login);
        user.setPasswd("pass");
        InformationBean rep = ms.saveUser(user);
        assertEquals(Constants.REPLY_403, rep);
        System.out.println("user was not saved "+user);     
}


@Service
public class MessagingService{
...

@Transactional(propagation=Propagation.REQUIRED)
public InformationBean saveUser(User user) {
    InformationBean info ;
    try {
        userDao.saveUser(user);
        info = Constants.REPLY_200;
    }catch(DataIntegrityViolationException ex) {
        logger.warn("login already used.");
        info = Constants.REPLY_403;
    }catch(ConstraintViolationException cve) {
        logger.warn("login already used.");
        info = Constants.REPLY_403;
    }
    catch(Exception e) {
        logger.error("Oups error",e);       
        info = Constants.REPLY_500;
    }

    return info;
}
...
}

这是完整的堆栈跟踪

DEBUG - Creating new transaction with name [com.myapp.service.MessagingService.saveUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d] for JPA transaction
DEBUG - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@79df82]
Hibernate: insert into User (email, login, passwd) values (?, ?, ?)
8928 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000
8929 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Duplicate entry 'u123456789012' for key 2
ERROR - Oups error
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.model.User]
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:674)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy32.persist(Unknown Source)
    at com.myapp.dao.hibernate.UserDaoImpl.saveUser(UserDaoImpl.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy34.saveUser(Unknown Source)
    at com.myapp.service.MessagingService.saveUser(MessagingService.java:237)
    at com.myapp.service.MessagingService$$FastClassByCGLIB$$48584635.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    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.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
    at com.myapp.service.MessagingService$$EnhancerByCGLIB$$4c0c06a9.saveUser(<generated>)
    at com.myapp.service.MessagingServiceTest.testSaveUser(MessagingServiceTest.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.model.User]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2836)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
    at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
    at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:800)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:774)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:778)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:668)
    ... 56 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'u123456789012' for key 2
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
    at com.mysql.jdbc.Util.getInstance(Util.java:384)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3562)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3494)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1960)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2114)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2696)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2105)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2398)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2316)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2301)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:101)
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
    ... 71 more
DEBUG - Initiating transaction commit
DEBUG - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d]
DEBUG - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d] after transaction
DEBUG - Closing JPA EntityManager

EDIT1:从 saveUser() DAO 方法中删除 throws Exception 后,Spring 异常转换似乎正在工作。我的服务方法捕获 DataIntegrityViolationException 并正常返回。然而,测试方法没有得到返回,而是得到一个异常:TransactionSystemException。我怎样才能避免这种不想要的异常破坏一切?

编辑2: Spring异常翻译工作正常,问题来自JPA/EntityManager。 查看完整的故事以及我如何解决它:http://tinyurl.com/439dmul

My dao class com.myapp.dao.hibernate.XyzDaoImpl is annotated with @Repository

@Repository
public class UserDaoImpl extends GenericDaoJpa implements UserDao {

...
    @Override
    public void saveUser(User user) throws Exception{
        entityManager.persist(user);
    }
...
}

My app-data.xml is as follow:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
       <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
       <property name="username" value="${db.username}" />
     <property name="password" value="${db.password}" />
     <property name="initialSize" value="5" />
        <property name="maxActive" value="0" />
  </bean>


    <!-- JPA Entity Manager Factory -->
    <bean id="entityManagerFactory"  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
          p:dataSource-ref="dataSource" p:jpaDialect-ref="jpaDialect"
        p:jpaVendorAdapter-ref="jpaVendorAdapter"
    />

    <bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
    </bean>

    <bean name="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"></property>
    </bean>

    <!-- detect les @persistentContext in dao -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


     <!-- This will ensure that hibernate or jpa exceptions are automatically translated into
         Spring's generic DataAccessException hierarchy -->
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>


 <bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />

    <!-- Transaction Config -->
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"
          p:entityManagerFactory-ref="entityManagerFactory"/>

   <context:component-scan base-package="com.myapp.dao.hibernate" />

 <tx:annotation-driven transaction-manager="txManager" />

Now, in my jUnit test method, I deliberately insert a duplicate object and I got javax.persistence.PersistenceException instead of a spring exception.

@Test public void testSaveUser() {
        String login = "duplicateLogin";

        User user = new User();
        user.setLogin(login);
        user.setPasswd("pass");
        InformationBean rep = ms.saveUser(user);
        assertEquals(Constants.REPLY_403, rep);
        System.out.println("user was not saved "+user);     
}


@Service
public class MessagingService{
...

@Transactional(propagation=Propagation.REQUIRED)
public InformationBean saveUser(User user) {
    InformationBean info ;
    try {
        userDao.saveUser(user);
        info = Constants.REPLY_200;
    }catch(DataIntegrityViolationException ex) {
        logger.warn("login already used.");
        info = Constants.REPLY_403;
    }catch(ConstraintViolationException cve) {
        logger.warn("login already used.");
        info = Constants.REPLY_403;
    }
    catch(Exception e) {
        logger.error("Oups error",e);       
        info = Constants.REPLY_500;
    }

    return info;
}
...
}

Here is the complete stack trace

DEBUG - Creating new transaction with name [com.myapp.service.MessagingService.saveUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d] for JPA transaction
DEBUG - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@79df82]
Hibernate: insert into User (email, login, passwd) values (?, ?, ?)
8928 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000
8929 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Duplicate entry 'u123456789012' for key 2
ERROR - Oups error
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.model.User]
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:674)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy32.persist(Unknown Source)
    at com.myapp.dao.hibernate.UserDaoImpl.saveUser(UserDaoImpl.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy34.saveUser(Unknown Source)
    at com.myapp.service.MessagingService.saveUser(MessagingService.java:237)
    at com.myapp.service.MessagingService$FastClassByCGLIB$48584635.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    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.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
    at com.myapp.service.MessagingService$EnhancerByCGLIB$4c0c06a9.saveUser(<generated>)
    at com.myapp.service.MessagingServiceTest.testSaveUser(MessagingServiceTest.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.myapp.model.User]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2836)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
    at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
    at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:800)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:774)
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:778)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:668)
    ... 56 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'u123456789012' for key 2
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
    at com.mysql.jdbc.Util.getInstance(Util.java:384)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3562)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3494)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1960)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2114)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2696)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2105)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2398)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2316)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2301)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:101)
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
    ... 71 more
DEBUG - Initiating transaction commit
DEBUG - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d]
DEBUG - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@f6852d] after transaction
DEBUG - Closing JPA EntityManager

EDIT1: After removing the throws Exception from the saveUser() DAO method, it seems that Spring exception translation is working. My service method catchs DataIntegrityViolationException and return normally. However, the test method doesn't get the return but instead get an exception: TransactionSystemException. How can I avoid such unwanted exception that breaks everything?

Edit2:
Spring exception translation was working fine, the problem comes from JPA/EntityManager.
See the complete story and how I managed to solve it: http://tinyurl.com/439dmul

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鼻尖触碰 2024-11-14 22:29:55

关于您关于 TransactionSystemException 的后一个问题:退出 @Transactional 方法时抛出此异常,以指示事务已回滚。

如果您想可靠地捕获约束违规,则需要在事务周围进行,而不是在事务内部进行。例如,通过在 saveUser() 方法内使用编程式事务划分而不是 @Transactional,或者通过在顶部添加 try-catch 子句,水平法。

Regarding your latter question about TransactionSystemException: this exception was thrown when exiting @Transactional method in order to indicate that transaction had been rolled back.

If you want to reliably catch constraint violations, you need to do it around transaction, not inside it. For example, by using programmatic transaction demarcation inside saveUser() method instead of @Transactional, or by adding try-catch clause to the top-level method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文