Spring事务没有正确回滚

时间:2018-01-08 13:40:43

标签: java spring transactions

@RunWith(SpringRunner.class)
@CustomTestContext
public class TransactionalTest {

    @Autowired
    private UserRepository userRepository;

    private Log logger = LogFactory.getLog(getClass());

    public void doSomething() {
        try {
            User user = new User();
            user.setUsername("test"); // username has unique constraint
            userRepository.save(user);
        } catch (DataIntegrityViolationException e) {
            logger.info("Wrong");
        }
    }

    @Test
    @Transactional
    public void doTest() {
        doSomething();
        doSomething();
    }

    @Test
    @Transactional
    public void doTest2() {
        doSomething();
        doSomething();
    }
}

doTest在第二个DataIntegrityViolationException来电中遇到doSomething时,第一个doSomething来电没有回滚,导致该用户使用了用户名" test& #34;仍然存在,导致doTest2两次doSomethong来电DataIntegrityViolationException

我期望当事务方法遇到异常时,它会回滚到第一个带有@Transactional注释的方法之前的状态,在上面的情况中根本没有向数据库插入任何新用户,由于默认传播值为REQUIRE

我将JpaTransactionManager日志记录级别转为DEBUG并获得如下控制台:

DEBUG o.s.o.jpa.JpaTransactionManager              - Creating new transaction with name [com.ray.spring.test.TransactionalTest.doTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG o.s.o.jpa.JpaTransactionManager              - Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@2ceca2ef]
INFO  o.s.t.c.t.TransactionContext                 - Began transaction (1) for test context [DefaultTestContext@3b42121d testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@7a2ab862, testMethod = doTest@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41fa769c testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@343e225a]; rollback [true]
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
WARN  o.h.e.j.spi.SqlExceptionHelper               - SQL Error: 1062, SQLState: 23000
ERROR o.h.e.j.spi.SqlExceptionHelper               - Duplicate entry 'test' for key 'UK_jreodf78a7pl5qidfh43axdfb'
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Setting JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] rollback-only
INFO  c.r.s.test.TransactionalTest                 - Wrong
DEBUG o.s.o.jpa.JpaTransactionManager              - Initiating transaction rollback
DEBUG o.s.o.jpa.JpaTransactionManager              - Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
DEBUG o.s.o.jpa.JpaTransactionManager              - Closing JPA EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
INFO  o.s.t.c.t.TransactionContext                 - Rolled back transaction for test context [DefaultTestContext@3b42121d testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@7a2ab862, testMethod = doTest@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41fa769c testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
// doTest2() below
DEBUG o.s.o.jpa.JpaTransactionManager              - Creating new transaction with name [com.ray.spring.test.TransactionalTest.doTest2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG o.s.o.jpa.JpaTransactionManager              - Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@17229821]
INFO  o.s.t.c.t.TransactionContext                 - Began transaction (1) for test context [DefaultTestContext@3b42121d testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@e829999, testMethod = doTest2@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41fa769c testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@343e225a]; rollback [true]
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
WARN  o.h.e.j.spi.SqlExceptionHelper               - SQL Error: 1062, SQLState: 23000
ERROR o.h.e.j.spi.SqlExceptionHelper               - Duplicate entry 'test' for key 'UK_jreodf78a7pl5qidfh43axdfb'
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Setting JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] rollback-only
INFO  c.r.s.test.TransactionalTest                 - Wrong
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
WARN  o.h.e.j.spi.SqlExceptionHelper               - SQL Error: 1062, SQLState: 23000
ERROR o.h.e.j.spi.SqlExceptionHelper               - Duplicate entry 'test' for key 'UK_jreodf78a7pl5qidfh43axdfb'
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Setting JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] rollback-only
INFO  c.r.s.test.TransactionalTest                 - Wrong
DEBUG o.s.o.jpa.JpaTransactionManager              - Initiating transaction rollback
DEBUG o.s.o.jpa.JpaTransactionManager              - Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
DEBUG o.s.o.jpa.JpaTransactionManager              - Closing JPA EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
INFO  o.s.t.c.t.TransactionContext                 - Rolled back transaction for test context [DefaultTestContext@3b42121d testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@e829999, testMethod = doTest2@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41fa769c testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].

似乎它确实已回滚但不影响第一次doSomething通话。

更新

我编辑我的代码如下:

@Transactional
public void doSomething() {
    logger.info("First save");
    userRepository.save(new User("test", "test"));
    logger.info("Second save");
    userRepository.save(new User("test", "test"));
}

@Test
@Transactional
public void doTest() {
    doSomething();
}

@Test
@Transactional
public void doTest2() {
    doSomething();
}

我已将@transactional添加到doSomething()并允许异常从doSomething投掷,但得到的结果相同:

DEBUG o.s.o.jpa.JpaTransactionManager              - Creating new transaction with name [com.ray.spring.test.TransactionalTest.doTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG o.s.o.jpa.JpaTransactionManager              - Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@42d6c12d]
INFO  o.s.t.c.t.TransactionContext                 - Began transaction (1) for test context [DefaultTestContext@7a2ab862 testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@33188612, testMethod = doTest@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@40113163 testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1a07bf6]; rollback [true]
INFO  c.r.s.test.TransactionalTest                 - First save
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
INFO  c.r.s.test.TransactionalTest                 - Second save
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
WARN  o.h.e.j.spi.SqlExceptionHelper               - SQL Error: 1062, SQLState: 23000
ERROR o.h.e.j.spi.SqlExceptionHelper               - Duplicate entry 'test' for key 'UK_jreodf78a7pl5qidfh43axdfb'
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Setting JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Initiating transaction rollback
DEBUG o.s.o.jpa.JpaTransactionManager              - Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com.ray.spring.model.User#1]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
DEBUG o.s.o.jpa.JpaTransactionManager              - Closing JPA EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
INFO  o.s.t.c.t.TransactionContext                 - Rolled back transaction for test context [DefaultTestContext@7a2ab862 testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@33188612, testMethod = doTest@TransactionalTest, testException = org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_jreodf78a7pl5qidfh43axdfb]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement, mergedContextConfiguration = [MergedContextConfiguration@40113163 testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
\\ doTest2() below
DEBUG o.s.o.jpa.JpaTransactionManager              - Creating new transaction with name [com.ray.spring.test.TransactionalTest.doTest2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG o.s.o.jpa.JpaTransactionManager              - Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@22d9ca63]
INFO  o.s.t.c.t.TransactionContext                 - Began transaction (1) for test context [DefaultTestContext@7a2ab862 testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@484149eb, testMethod = doTest2@TransactionalTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@40113163 testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@1a07bf6]; rollback [true]
INFO  c.r.s.test.TransactionalTest                 - First save
DEBUG o.s.o.jpa.JpaTransactionManager              - Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating in existing transaction
DEBUG org.hibernate.SQL                            - insert into User (password, username) values (?, ?)
WARN  o.h.e.j.spi.SqlExceptionHelper               - SQL Error: 1062, SQLState: 23000
ERROR o.h.e.j.spi.SqlExceptionHelper               - Duplicate entry 'test' for key 'UK_jreodf78a7pl5qidfh43axdfb'
DEBUG o.s.o.jpa.JpaTransactionManager              - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Setting JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] rollback-only
DEBUG o.s.o.jpa.JpaTransactionManager              - Initiating transaction rollback
DEBUG o.s.o.jpa.JpaTransactionManager              - Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
DEBUG o.s.o.jpa.JpaTransactionManager              - Closing JPA EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
INFO  o.s.t.c.t.TransactionContext                 - Rolled back transaction for test context [DefaultTestContext@7a2ab862 testClass = TransactionalTest, testInstance = com.ray.spring.test.TransactionalTest@484149eb, testMethod = doTest2@TransactionalTest, testException = org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_jreodf78a7pl5qidfh43axdfb]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement, mergedContextConfiguration = [MergedContextConfiguration@40113163 testClass = TransactionalTest, locations = '{file:src/main/resources/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{file:src/main/resources/application.properties}', propertySourceProperties = '{mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].

它有Participating transaction failed - marking existing transaction as rollback-only行,但doTest2在第一次userRepository.save()尝试时仍然失败,意味着用户使用" test"名称已存在。

是否意味着当同一事务中发生某些异常时,第一个save无法回滚?

CustomTestContxt.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration("file:src/main/resources/applicationContext.xml")
@TestPropertySource(
        locations = {"file:src/main/resources/application.properties"},
        properties = {"mysql.Url = jdbc:mysql://localhost:3306/springtest?characterEncoding=UTF-8&serverTimezone=UTC"})
public @interface CustomTestContext {
}

UPDATE2:

@Test
@Transactional
@Rollback
public void doTest() {
    entityManager.persist(new User("test", "test"));
}

@Test
@Tranactional
public void doTest2() {
    logger.info(entityManager.find(User.class, 1L));
}

并记录:

INFO  c.r.s.test.TransactionalTest          - User{id=1, username='test', password='test', roles=[]}

1 个答案:

答案 0 :(得分:0)

doSomething()正在捕获异常。

只有在使用@Transactional公布的方法中抛出RuntimeException时,才会回滚事务。

如果你想保留代码,你必须手动回滚doSomething()中的事务

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

第二个选项是将doSomething()标记为事务性,然后不捕获事务。然后必须在测试方法中完成事务处理。