2

我正在尝试编写一段代码,在其中我可以看到 @Transaction 方法在 RuntimeException 上回滚。这应该是预期的默认行为,但这不是我所看到的。任何想法为什么?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:mrpomario/springcore/jdbc/jdbc-testenv-config.xml")
@Transactional // Will rollback test transactions at the end
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TransactionalTest
{
    @Autowired
    FeedManagerOne feedManagerOne;

    @Test
    public void test_RuntimeExceptions_Rollback_Behaviour(){
         Feed bogus = new Feed("B", "B", false);

         assertFalse(feedManagerOne.exists(bogus));

         try {
              feedManagerOne.createFeedAndThrowRuntimeException(bogus);
         }  catch (RuntimeException e) { }

         // WRONG! feedManagerOne.exists(bogus) SHOULD return false, but returns true.
         assertFalse(feedManagerOne.exists(bogus));
    }

}

我的服务:

@Service
public class FeedManagerOne {
    @Autowired
    JdbcTemplate jdbcTemplate;

    @Transactional(readOnly = true)
    public boolean exists(Feed feed) {
        String query = "SELECT COUNT(*) FROM feed WHERE name = ? AND url = ? AND is_active = ?";
        int total = jdbcTemplate.queryForInt(query, feed.getName(), feed.getUrl(), feed.isActive());
        boolean found = (total == 1);

        return found;
    }

    @Transactional
    public boolean createFeedAndThrowRuntimeException(Feed feed) {
        String query = "INSERT INTO feed (name, url, is_active) values (?, ?, ?)";
        int rowsChanged = jdbcTemplate.update(query, feed.getName(), feed.getUrl(), feed.isActive());
        boolean created = (rowsChanged == 1);

        if (true)
        {
            throw new RuntimeException();
        }

        return created;
    }
}

这就是我定义我的 TransactionManager 的方式:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
    <jdbc:embedded-database id="dataSource" type="H2">
    <jdbc:script location="mrpomario/springcore/jdbc/testdb/schema.sql"/>
    <jdbc:script location="classpath:mrpomario/springcore/jdbc/testdb/test-data.sql"/>
</jdbc:embedded-database>
4

1 回答 1

5

这是预期的行为。

当您从方法中抛出异常(应该导致回滚)时@Transactional,Spring 会将事务标记为在其结束时回滚。因此,如果您从调用堆栈中最顶层的方法抛出异常@Transactional,事务将立即回滚。

但是在您的情况下,您的测试方法也是@Transactional如此,因此您有一个跨越整个测试方法的事务。这意味着尽管事务在调用之后被标记为回滚createFeedAndThrowRuntimeException(),但直到测试方法结束才回滚,因此第二次调用exists()可以观察到变化。

因此,如果您想查看回滚,则需要使您的测试方法成为非事务性的。

我也没有<tx:annotation-driven/>在您的配置中看到。

于 2012-10-03T16:38:12.017 回答