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()、テスト メソッドが終了するまでロールバックされないため、 の 2 回目の呼び出しでexists()変更を確認できることを意味します。

したがって、ロールバックを確認したい場合は、テスト メソッドを非トランザクションにする必要があります。

<tx:annotation-driven/>また、あなたの構成には表示されません。

于 2012-10-03T16:38:12.017 に答える