Junit测试在交易后没有回滚

时间:2014-05-04 18:20:00

标签: spring hibernate junit spring-transactions

我试图对一些持久性代码进行单元测试,并且我遇到了数据库挂起到以前测试中创建的行的问题。我也在使用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>

4 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

尝试添加事务拦截器:

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

答案 2 :(得分:0)

扩展AbstractTransactionalJunit4SpringContextTests或添加@TestExecutionListeners(TransactionalTestExecutionListener.class)。

答案 3 :(得分:0)

所以,我终于通过在BoneCPDatasource上指定defaultAutoCommit = false来实现这一点。 AFAIK对于这种配置来说太低了,因此可能是错误的。但至少它正在发挥作用。