@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=[]}
答案 0 :(得分:0)
doSomething()正在捕获异常。
只有在使用@Transactional公布的方法中抛出RuntimeException时,才会回滚事务。
如果你想保留代码,你必须手动回滚doSomething()中的事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
第二个选项是将doSomething()标记为事务性,然后不捕获事务。然后必须在测试方法中完成事务处理。