1

ドキュメントと一致しない奇妙な動作が見られます。これが私がやっていることです: Test クラスから、DB に行を作成する @Transactional Service を呼び出してから、RunTimeException をスローする別の @Transactional Service (REQUIRES_NEW とマークされている) を呼び出します。テストの最後に自分の記録が表示されることを期待していますが、そうではありません。アイデア?

私のテストクラス:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:**/jdbc-beans.xml","classpath:**/jdbc-infrastructure.xml","classpath:**/jdbc-infrastructure-test.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TransactionalTest {

   @Autowired
   FeedManagerOne feedManagerOne;

   @Test
   public void test_propagation_REQUIRES_to_REQUIRES_NEW() {
      Feed anotherFeed = new Feed("AnotherRSS", "http://www.anotherfeedlink.com", true);
      assertFalse(feedManagerOne.exists(anotherFeed)); // EVALUATES TO FALSE

      try { 
         feedManagerOne.createFeed(anotherFeed, true);
      } catch (RuntimeException e) {
         e.printStackTrace();
      }

      // EVALUATES TO FALSE. WRONG! IT SHOULD BE TRUE.
      assertTrue(feedManagerOne.exists(anotherFeed)); 
   }
}

サービス 1:

@Service
public class FeedManagerOne {

   @Autowired
   FeedManagerTwo feedManagerTwo;

   @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 createFeed(Feed feed, boolean invokeFeedManagerTwo) {
      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);

      // WHEN THE THE FOLLOWING METHOD THROWS A RUNTIME EXCEPTION,
      // THE JUST CREATED RECORD WILL BE LOST FROM THE DB (SEE TEST)
      feedManagerTwo.throwRuntimeExceptionFromRequiresNew();

      return created;
   }        
}

サービス 2

@Service
public class FeedManagerTwo {
   @Transactional(propagation = Propagation.REQUIRES_NEW,  isolation = Isolation.READ_COMMITTED)
   public void throwRuntimeExceptionFromRequiresNew() {
      if (true) {
         throw new RuntimeException("From REQUIRES_NEW");
      }
   }
}
4

1 に答える 1

2

ドキュメントと完全に一致しています。内部サービスは例外をスローするため、そのトランザクションはロールバックされます。次に、例外が外部サービスに伝播し、外部トランザクションもロールバックされます。

外部サービス内で例外をキャッチすると、ロールバックしなくなります。

于 2012-10-04T16:57:38.007 に答える