Junit测试在事务后不回滚
Posted
技术标签:
【中文标题】Junit测试在事务后不回滚【英文标题】:Junit test not rolling back after transaction 【发布时间】:2014-05-04 18:19:59 【问题描述】:我正在尝试对一些持久性代码进行单元测试,但遇到了数据库挂在先前测试中创建的行上的问题。我也在使用 Hibernate Search,虽然这没有反映在我在这里分享的代码中。
我正在使用 Spring 3.1.x、Hibernate 4.x 和 HSQLDB 2.3.2
日志
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.UserRole#1]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
***First test****
DEBUG - AbstractPlatformTransactionManager.processRollback(843) | Initiating transaction rollback
DEBUG - HibernateTransactionManager.doRollback(496) | Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.User#1],EntityKey[nl.project.model.user.UserRole#1],EntityKey[nl.project.model.user.UserRole#2], EntityKey[nl.project.model.user.UserRole#3]],collectionKeys=[CollectionKey[nl.project.model.user.User.roles#1]]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
DEBUG - HibernateTransactionManager.doBegin(342) | Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - HibernateTransactionManager.doBegin(352) | Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
DEBUG - HibernateTransactionManager.doBegin(413) | Exposing Hibernate transaction as JDBC transaction [com.jolbox.bonecp.ConnectionHandle@73d17d67]
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: select this_.userRoleId as userRole1_92_0_, this_.label as label2_92_0_ from UserRole this_
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.UserRole#3], EntityKey[nl.project.model.user.UserRole#2], EntityKey[nl.project.model.user.UserRole#1]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
WARN - SqlExceptionHelper.logExceptions(144) | SQL Error: -104, SQLState: 23505
ERROR - SqlExceptionHelper.logExceptions(146) | integrity constraint violation: unique constraint or index violation; UK_O0VIK8LBO8UYMR8WUDN5T21QX table: USERROLE
代码
@Entity
@Immutable
@Table
@NaturalIdCache(region=CacheRegion.NATURAL)
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,region=CacheRegion.USER)
public class UserRole implements Serializable
public static final String ROLE_ANONYMOUS="ROLE_ANONYMOUS";
public static final String ROLE_USER="ROLE_USER";
public static final String ROLE_PROVENDOR="ROLE_PROVENDOR";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable=false, updatable=false)
private Long id;
@Column(nullable=false,unique=true,updatable=false)
@NaturalId
private String label;
...
代码
public class CoreTest extends TestCase
@Inject
protected SimpleManager<Long> simpleMgr;
public void baseSetup()
simpleMgr.flush();
simpleMgr.clear();
//after 1st test this contains all created UserRoles
List roles = simpleMgr.getAll(UserRole.class);
UserRole role = new UserRole(UserRole.ROLE_ANONYMOUS);
simpleMgr.save(role);
role = new UserRole(UserRole.ROLE_USER);
simpleMgr.save(role);
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =
"classpath:/spring/applicationContext.xml"
"classpath:/spring/applicationContext-transaction.xml")
public class MyManagerTest extends CoreTest
@Before
public void methodSetup()
super.baseSetup();
role = new UserRole(UserRole.ROLE_PROUSER);
simpleMgr.save(role);
simpleMgr.save(userMgr.createUser("marc", "marc@gmail.com"));
simpleMgr.flush();
@Test
@Transactional
public void test1()
...
@Test
@Transactional
public void test2()
....
事务管理
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="mainDataSource"/>
</bean>
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="$jdbc.driverClassName"/>
[...]
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.connection.driver_class=$jdbc.driverClassName
hibernate.jdbc.batch_size=30
hibernate.dialect=$hibernate.dialect
hibernate.connection.autoReconnect=true
hibernate.connection.autoReconnectForPools=true
hibernate.connection.autocommit=false
</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
【问题讨论】:
尝试在您的测试中添加@Rollback(true)
注释。
谢谢。没有区别
可能是因为你没有清理你的数据?
我还尝试使用 rollback=true 显式指定事务管理。没有帮助,这是 Spring 设置的默认值。日志表明回滚实际上正在发生,它似乎没有传播到数据库
清理是什么意思?回滚表明不需要显式清理?
【参考方案1】:
尝试在测试类上添加@Transactional 注解。 http://docs.spring.io/spring/docs/2.0.x/api/org/springframework/transaction/annotation/Transactional.html
【讨论】:
是的,这没有帮助【参考方案2】:尝试添加事务拦截器:
<beans xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
【讨论】:
这里有,我没有在示例中包含这个【参考方案3】:扩展 AbstractTransactionalJunit4SpringContextTests 或添加 @TestExecutionListeners(TransactionalTestExecutionListener.class)。
【讨论】:
不确定这是否会有所帮助,因为它只是一个方便类,用于似乎已经存在的东西 我以前遇到过一个问题,因为缺少@TestExecutionListeners(TransactionalTestExecutionListener.class)。 顺便说一下,你扩展了TestCase——你用的是什么版本的junit? (在 Junit4 中不需要扩展任何东西)。【参考方案4】:所以,我终于通过在 BoneCPDatasource 上指定 defaultAutoCommit=false 来完成这项工作。 AFAIK 这对于这种配置来说太低了,因此可能是错误的。但至少它是有效的。
【讨论】:
以上是关于Junit测试在事务后不回滚的主要内容,如果未能解决你的问题,请参考以下文章
spring hibernate 事务整合 使用测试类 事务不自动提交的问题!!!