【问题标题】:How to rollback test如何回滚测试
【发布时间】:2012-06-15 13:05:17
【问题描述】:

这是我的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:repositoryContextTest.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class SeasonITest {
@Autowired
private SeasonDao seasonDao;

@Test
public void createSeason() throws Exception {
    Season season = new Season();
    season.setName("2012");
    seasonDao.createSeason(season);
}

以及我的 bean 配置文件中的数据源

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/tournament_system" />
    <property name="username" value="root" />
    <property name="password" value="root" />
    <property name="defaultAutoCommit" value="false"/>
    <property name="poolPreparedStatements" value="false"/>
    <property name="maxOpenPreparedStatements" value="0"/>
 </bean>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

当我运行此测试时,会在我的数据库中创建一条新记录。

我怎样才能回滚这个事务?

这是我看到的日志输出:

2012-06-15 15:00:02,173 [main] INFO  - ionalTestExecutionListener - 
 Rolled back transaction after test execution for test context 
 [[TestContext@76db09 testClass = SeasonITest, 
   locations = array<String>['classpath:repositoryContextTest.xml'], 
   testInstance = org.toursys.repository.dao.SeasonITest@1265109, 
   testMethod = createSeason@SeasonITest, testException = [null]]]

更新:

下面的所有答案都想改变我不想要的逻辑或数据库引擎。所以我提供了正确答案的声誉点:

为什么当我有这个时:@TransactionConfiguration(defaultRollback = true) 在事务配置测试中没有回滚,我该如何修复它?

【问题讨论】:

    标签: java spring


    【解决方案1】:

    如果您使用 MySQL 和 MyISAM 引擎,请尝试切换到 InnoDB。

    对于更复杂的测试,您可能需要一个模拟框架或数据库重建。

    编辑1: 根据文档,InnoDB 是事务性的,完全支持 ACID,而 MyISAM 支持原子操作。更多阅读:Transaction and Atomic Operation Differences

    编辑2: 在@TransactionConfiguration 中,defaultRollback 的默认值为 true,因此您应该添加 @TransactionConfiguration(defaultRollback=false)

    而不是注释该行

    【讨论】:

    • hm 非常好用,InnoDB 和 MyISAM 有什么不同?
    • hm 但是在我更换引擎之后。并评论 defaultRollback = true 那么这条记录不会保存在我的数据库中
    • @hudi 将 defaultRollback 显式设置为 false 有帮助吗?
    • 是的,我忘记了默认值为 true,所以当我设置为 false 时,我可以看到新记录,但为什么回滚在 MIsam 引擎中不起作用?
    • 根据文档 MyISAM 是一个非事务性数据库引擎,因此它不支持事务。这就是回滚不起作用的原因。我认为您可以通过锁定表来模拟开始事务->...->提交,但只要所有行都动态保存,您就无法回滚。如需进一步说明,请阅读所提供链接后的文档。
    【解决方案2】:

    从表面上看,您的代码和配置看起来是正确的。但是,能否请您发布您的 SeasonsDAO 对象。我们首先需要验证 SeasonsDAO 是否为交易正确配置。

    SeasonsDAO 需要参与与您的测试用例相同的 TransactionContext,并且无法使用您发布的代码进行验证。

    您是否将 SeasonsDAO 标记为 @Transactional ?

    如果不是,我不确定 TransactionProxyFactoryBean 将如何代理和以声明方式管理事务。

    在高层次上,spring 使用代理的概念来执行许多服务,例如事务管理。

    如果您将某些内容标记为@Transactional,Spring 将动态创建一个代理,该代理将实现与您的目标类相同的接口。一旦被代理,事务拦截器将包​​装对目标类的方法调用,并根据您可能指定的默认值或规则决定是回滚还是提交。

    【讨论】:

    • 那么我很确定您的 SeasonsDAO 没有在事务中运行,因此不会回滚插入。
    • 问题得到了回答,测试被注释为事务性的,所以我认为这就足够了
    【解决方案3】:

    还有其他解决方案:

    1. 使用模拟框架(即 Mockito)模拟数据源。这样,您将只测试您的 DAO 逻辑
    2. 使用可以为每个测试设置的单独数据库进行测试。您可以使用 DBUnit 来执行此操作。
    3. 使用内存数据库(即 HSQL),这样更改就不会持续存在。

    这样您就不必回滚更改。

    【讨论】:

      【解决方案4】:

      请确保您必须声明:

      <tx:annotation-driven transaction-manager="transactionManager" /> 
      

      在你的 spring 配置文件中,例如(applicationContext.xml)。

      正如@Lieber 已经解释的,但更多解释是:MySQL 服务器(版本 3.23-max 和所有版本 4.0 及更高版本)支持使用 InnoDB 事务存储引擎的事务。 InnoDB 提供完全的 ACID 合规性。请参阅第 14 章,存储引擎。有关 InnoDB 在事务错误处理方面与标准 SQL 的差异的信息,请参阅第 14.3.13 节,“InnoDB 错误处理”。

      MySQL Server 中的其他非事务性存储引擎(例如 MyISAM)遵循不同的数据完整性范式,称为“原子操作”。在事务方面,MyISAM 表实际上总是在 autocommit = 1 模式下运行。原子操作通常提供可比的完整性和更高的性能。所以,MyISAM 事务存储引擎总是自动提交事务。

      【讨论】:

        【解决方案5】:

        尝试用@Transactional注释测试方法

        【讨论】:

          【解决方案6】:

          哈哈,三天前我也遇到过同样的事情。尝试将 transactionManager ="transactionManager" 添加到您的 @contextConfiguration:

          @RunWith(SpringJUnit4ClassRunner.class)
          @ContextConfiguration(locations = {"classpath:PersistenceHelper-context.xml"})
          @TransactionConfiguration(defaultRollback = true, transactionManager = "transactionManager")
          @Transactional
          

          另外,我对此不是 100% 确定,但您的 XML 文件应该遵循“*-context”格式。如果您想查看我的 PersistenceHelper-context.xml 文件,请告诉我。

          【讨论】:

            【解决方案7】:
            • 尝试扩展AbstractTransactionalJUnit4SpringContextTests
            • 注意MySql MISAM表不是事务性的,需要使用INNODB类型的表(见herehere
            • 您的 DAO 是否也标有 @Transactional?这可能会导致问题(请参阅here

            【讨论】:

              【解决方案8】:

              在您的测试用例逻辑之后尝试以下方法。

              TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
              

              【讨论】:

              • 这段代码抛出异常:org.springframework.transaction.NoTransactionException:范围内没有事务方面管理的TransactionStatus
              【解决方案9】:

              您的 Dao 需要标记为 @Transactional。

              还要注释您的测试:

              @TestExecutionListeners(TransactionalTestExecutionListener.class)  //Rolls back transactions by default
              

              【讨论】:

              • 当我添加你的符号时,我在这一行得到了 NPE:seasonDao.createSeason(season);
              猜你喜欢
              • 2022-12-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-01-28
              • 2016-04-26
              • 2011-12-29
              相关资源
              最近更新 更多