Ванильное обновление JDBC не откатывается в весеннем модульном тесте

У меня есть весенний модульный тест для метода DAO, который вставляется в две разные таблицы. После завершения теста одна из вставок откатывается, как и ожидалось, но нет другой! Я действительно не могу понять, что происходит. Я несколько раз отлаживал тест, чтобы видеть, когда (незафиксированные) изменения появляются в базе данных, но затем исчезает только одно.

Единственная разница, которую я вижу, заключается в том, что в одном случае вставка выполняется с помощью необработанного JDBC, а во втором случае - с JdbcTemplate Sping. Но разве оба не должны быть в одной и той же транзакции, которая затем откатывается?

Вот мой тестовый класс:

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

Мой test-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(event), чтобы вставка происходила только одна. Конечный результат тот же: первая вставка не откатывается. Таким образом, кажется, проблема с транзакцией для первой вставки.

Обновление 2. Я переработал первую вставку, чтобы она также использовала JdbcTemplate, и теперь все работает нормально! Таким образом, вопрос можно перефразировать так: как заставить ванильный код JDBC откатиться в весеннем модульном тесте?


person Nicola Ambrosetti    schedule 05.05.2017    source источник
comment
Возможно ли, что createMyObjectEvent имеет собственную транзакцию? Например. myDao аннотирован таким образом?   -  person Uwe Allner    schedule 05.05.2017
comment
На MyDao нет аннотаций. Вся конфигурация за пределами модульного теста исходит из XML.   -  person Nicola Ambrosetti    schedule 05.05.2017
comment
Почему вы используете новый JdbcTemplate во втором методе?   -  person Nemesis    schedule 05.05.2017
comment
Потому что так код был написан давным-давно...   -  person Nicola Ambrosetti    schedule 05.05.2017
comment
Возможный дубликат отката транзакции в тестах Spring JDBC   -  person Nicola Ambrosetti    schedule 06.05.2017


Ответы (1)


@Rollback нужна транзакция, управляемая Spring, чтобы работай. Для участия в Spring управляемой транзакции проще всего использовать JDBCTemplate или DataSourceUtils. Оба содержат код, необходимый для использования управляемой транзакции spring.

person ikettu    schedule 05.05.2017
comment
Ты прав! Необработанное соединение jdbc не участвует в транзакции, если я не создам его с помощью DataSourceUtils.getConnection(dataSource). Это то, что внутри используется JdbcTemplate. См. также stackoverflow.com/questions/4048340/ - person Nicola Ambrosetti; 06.05.2017