2012-10-04 2 views
1

문서와 일치하지 않는 이상한 동작이 나타납니다. 이것은 내가하고있는 일이다. Test 클래스에서 DB에 행을 생성 한 다음 @Transactional Service (REQUIRES_NEW로 표시된)를 호출하여 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)); 
    } 
} 

서비스 하나 :

@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; 
    }   
} 

서비스 두

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

답변

3

그것은 문서와 완전히 일치합니다. 내부 서비스가 예외를 throw하므로 트랜잭션이 롤백됩니다. 그런 다음 예외가 외부 서비스로 전달되어 외부 트랜잭션도 롤백됩니다.

외부 서비스에서 예외를 catch하면 더 이상 롤백되지 않습니다.