2017-05-05 4 views
1

두 개의 다른 테이블에 삽입하는 DAO 메소드의 스프링 유닛 테스트가 있습니다. 테스트가 완료되면 삽입물 중 하나가 예상대로 롤백되지만 은 다른 하나가 아닙니다.! 나는 정말로 무슨 일이 일어나는지 알 수 없다. 필자는 테스트를 여러 번 디버깅하여 (커밋되지 않은) 변경 사항이 데이터베이스에 표시되는 시점을 확인할 수 있지만 그 중 하나만 사라지는 경우를 확인할 수 있습니다.바닐라 JDBC 업데이트가 스프링 유닛 테스트에서 롤백되지 않음

내가 볼 수있는 유일한 차이점은 삽입이 원시 JDBC로 수행되고 두 번째 경우에는 Sping의 JdbcTemplate으로 수행된다는 것입니다. 그러나 둘 다 롤백 된 동일한 트랜잭션에 있지 않아야합니까?

여기 내 테스트 클래스의 :

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath:spring/test-context.xml"}) 
@Rollback 
@Transactional(transactionManager = "txManager") 
public class MyDaoIntegrationTest { 
    @Autowired 
    private DataSource dataSource; 
    @Autowired 
    private MyDao myDao; 

    @Test 
    public void createMyObject_test() throws Exception { 
     MyObject myObject = new MyObject(); 

     myDao.createMyObject(myObject, 123L); 
    } 
} 

내 시험의 context.xml은 다음과 같습니다

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=" 
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 

<bean id="myDao" class="my.package.myDao"> 
    <constructor-arg name="dataSource" ref="dataSource"/> 
</bean> 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="url" value="${unit.test.db.url}"/> 
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> 
    <property name="username" value="${unit.test.db.user}"/> 
    <property name="password" value="${unit.test.db.pass}"/> 
</bean> 

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource"/> 
</bean> 

</beans> 

약 (등 폐쇄 연결에 소음 제거) 보이는 테스트 할 수있는 방법 정도 :

public void createMyObject(MyObject vo, long refId) throws SQLException { 

    Connection cn = dataSource.getConnection(); 
    PreparedStatement ps = cn.prepareStatement("insert into MY_OBJECT (COL1, COL, ...)) values (?,?,...)"); 
    ps.setInt(1, vo.getCol1()); 
    ps.setInt(2, vo.getCol2()); 
     ... 
    ps.executeUpdate(); 

    MyObjectEventVO event = new MyObjectEventVO(); 
    createMyObjectEvent(event); 
} 

public void createMyObjectEvent(MyObjectEventVO vo) throws DataAccessException { 

    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
    String updateSql = 
      "insert into MY_OBJECT_EVENT(COL1, COL2, ...) " 
        + "values (?, ?, ...)"; 
    Object[] params = {vo.getCol1(), vo.getCol2(), ... }; 
    int[] types = {Types.INTEGER, Types.VARCHAR, ...}; 

    jdbcTemplate.update(updateSql, params, types); 
} 

업데이트 createMyObjectEvent (이벤트)에 대한 호출을 주석 처리하여 하나의 삽입 만 발생하도록했습니다. 최종 결과는 동일합니다. 첫 번째 삽입은 롤백되지 않습니다. 따라서 첫 번째 삽입에 대한 트랜잭션에 문제가있는 것으로 보입니다.

업데이트 2 JdbcTemplate도 사용하도록 첫 번째 삽입을 리팩토링 한 다음 모든 것이 잘 작동합니다! 따라서 질문은 바닐라 JDBC 코드를 스프링 유닛 테스트에서 롤백하는 방법으로 표현할 수 있습니다.

+0

createMyObjectEvent에 고유 한 트랜잭션이있을 수 있습니까? 예 : 이런 식으로 주석이 달린 myDao입니까? –

+0

MyDao에 주석이 없습니다. 단위 테스트 외부의 모든 구성은 XML에서 제공됩니다. – inovaovao

+0

두 번째 방법에서 새 JdbcTemplate을 사용하는 이유는 무엇입니까? – Nemesis

답변

1

@Rollback은 스프링 관리 트랜잭션이 작동해야합니다. 스프링 관리 트랜잭션을 가장 쉽게 참여하려면 JDBCTemplate 또는 DataSourceUtils을 사용하십시오. 둘 다 스프링 관리 트랜잭션을 사용하는 데 필요한 코드가 들어 있습니다.

+0

네가 맞아! 원시 jdbc 연결은 DataSourceUtils.getConnection (dataSource)을 사용하여 생성하지 않으면 트랜잭션에 참여하지 않습니다. 이것이 JdbcTemplate에서 내부적으로 사용하는 것입니다. http://stackoverflow.com/questions/4048340/transaction-rollback-on-spring-jdbc-tests를 참조하십시오. – inovaovao

관련 문제