Spring 3.1和Hibernate 4无法回滚JDBC事务

3

我在设置一个能够回滚的JUnit测试时遇到了麻烦。在决定提问之前,我已经阅读了几篇相关帖子,但似乎没有一个可以解决我的问题。

第二个测试用例失败了,因为第一个测试用例中插入并持久化了数据。

这是JUnit测试代码:

package com.company.group.spring.dao;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import com.company.group.spring.model.BusObj;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:NAME_OF_CONFIG_FILE.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@TestExecutionListeners({TransactionalTestExecutionListener.class,
    DependencyInjectionTestExecutionListener.class}) 
public class PerPartsWCDAOTest {

    @Autowired
    @Qualifier("myBusObjDAO")
    private BusObjDAO busObj_dao;

    @Transactional
    @Test
    public void testInsertRollback() {
        try {
        BusObj busObj = new BusObj("some data...");

        assertNotNull(busObj_dao);
        assertNotNull(busObj);

        busObj_dao.insert(perPartWC);
        }
        catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    @Transactional
    @Rollback(false)
    @Test
    public void testInsert() {
        BusObj busObj2 = new BusObj("some data...");

        busObj_dao.insert(perPartWC2);
    }

}

这是DAOImpl类(我试图测试的类):
```

以下是DAOImpl类(即我想要测试的类):

```
package com.company.group.spring.dao;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.company.group.spring.model.BusObj;

@Repository("myBusObjDAO")
public class myBusObjDAOImpl implements myBusObjDAO {

private NamedParameterJdbcTemplate jdbcTemplate;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

@Override
public void insert(BusObj someObj) {
    String sql = "insert into TABLE (args...) " +
            "VALUES (:named_params....)";

    SqlParameterSource paramSource = new BeanPropertySqlParameterSource(someObj);

    jdbcTemplate.update(sql, paramSource);
}

相关配置的一部分:

  <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />


  <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
      <property name="url" value="jdbc:oracle:thin:@SERVER:PORT:DB"/>
      <property name="username" value="USER"/>
      <property name="password" value="XXXXXX"/>

  </bean>

编辑:+调试打印

2012-12-18 08:50:42,177 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

2012-12-18 08:50:42,342 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction

2012-12-18 08:50:42,344 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]

2012-12-18 08:50:42,361 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler@128647a[valid=true]]

2012-12-18 08:50:42,390 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update

2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into TABLE (args...) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]

2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Fetching JDBC Connection from DataSource

2012-12-18 08:50:42,657 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Registering transaction synchronization for JDBC Connection

2012-12-18 08:50:42,671 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows

2012-12-18 08:50:42,678 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection()] Returning JDBC Connection to DataSource

2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback

2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]

2012-12-18 08:50:42,693 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction

更新: 我注意到日志中正在尝试回滚一个Hibernate事务(但这是JDBC)。然后我注意到"txManager"的类目前为org.springframework.orm.hibernate4.HibernateTransactionManager,因此我尝试使用org.springframework.jdbc.datasource.DataSourceTransactionManager重启应用,回滚工作正常了。所以我认为我的问题更具体地说是如何配置使用Hibernate和JDBC... 我仍然不知道哪里出了问题。


这里是相关的(我认为)调试日志...如果我漏掉了什么,请告诉我。 - user1766760
2个回答

0
我的问题解决方案是指定了 HibernateTransactionManager 的 dataSource。这里是关于 HibernateTransactionManager 的文档。
所以我想这可能是我在原始帖子中没有发布如何定义 txManager 的错误。
  <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="mySessionFactory"/>
  </bean>

更改为:

  <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="mySessionFactory"/>
    <property name="dataSource" ref="dataSource" />
  </bean>

我还在SessionFactory定义中添加了<property name="dataSource"><ref local="dataSource"/></property>,但如果我只关心JdbcTemplate,则似乎不必要。但是如果其中混合了HQL,则可能需要。

当它正在工作时,调试打印看起来像这样。我看到的唯一区别是在初始化回滚之前缺少了这行Returning JDBC Connection to DataSource

2012-12-19 08:14:29,455 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

2012-12-19 08:14:29,512 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction

2012-12-19 08:14:29,514 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]

2012-12-19 08:14:29,539 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler@1289e48[valid=true]]

2012-12-19 08:14:29,558 [main] DEBUG [com.company.group.spring.dao.MyClassDAOImpl.insert()] Session Factory is: org.hibernate.internal.SessionFactoryImpl@1285252

2012-12-19 08:14:29,569 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update

2012-12-19 08:14:29,570 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into MY_CLASS (COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8, COL9) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]

2012-12-19 08:14:29,608 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows

2012-12-19 08:14:29,611 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback

2012-12-19 08:14:29,612 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]

2012-12-19 08:14:29,680 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction

0

你的JUnit和DAO类看起来很好。

问题可能是在事务回滚之前连接自动提交了。你能否更改dataSource bean以包括defaultAutoCommit属性?

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
      <property name="url" value="jdbc:oracle:thin:@SERVER:PORT:DB"/>
      <property name="username" value="USER"/>
      <property name="password" value="XXXXXX"/>
      <property name="defaultAutoCommit" value="false" /> 
</bean> 

如果这个方法没有起作用的话,你能贴出你的控制台日志吗?

我已经尝试过了,但是没有任何插入被提交。如果我必须编程调用提交,我怀疑这会远离声明式事务...如果可能的话,我想避免这种情况。 - user1766760
此外,看起来它相当具有侵入性,并且如果我理解正确的话,会将我们绑定到Spring。考虑第11.6节[http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html]。 - user1766760

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接