@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”的用户仍然存在,并导致doTest2的两个调用抛出doSomethong

我期望的是,当事务方法遇到异常时,它将回滚到第一个带有DataIntegrityViolationException批注的方法运行之前的状态,在上述情况下,由于默认传播值,根本没有向数据库插入任何新用户。是@Transactional

我将REQUIRE日志记录级别更改为JpaTransactionManager,并得到如下所示的控制台:

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]]].


似乎它回滚了,但不影响第一个DEBUG调用。

更新:

我按如下方式编辑代码:

@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();
}


我已经将doSomething添加到@transactional并从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]]].


它具有行doSomething,但是Participating transaction failed - marking existing transaction as rollback-only在第一次尝试时仍然失败,这意味着具有“测试”名称的用户已经存在。

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

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 {
}


更新2:

@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=[]}

最佳答案

doSomething()正在捕获异常。

仅当在@Transactional注释的方法中抛出RuntimeException时,才会回滚事务。

如果要保留原样的代码,则必须在doSomething()中手动回滚事务

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();


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

关于java - Spring 交易未正确回滚,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48151514/

10-09 00:39