Spring TransactionManager - коммит не работает

Я пытаюсь создать Spring-решение для запуска пакета SQL-запросов на сервере MySQL 5.5. Под "запросом" я подразумеваю любой оператор SQL, который компилируется, поэтому пакетное задание SQL может содержать, например, несколько операторов CREATE TABLE, DELETE и затем INSERT.

Я использую Spring Batch для этой цели.

я имею transactionManager настраивается следующим образом.

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

и dataSource:

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="${batch.jdbc.driver}" />
    <property name="url" value="${batch.jdbc.url}" />
    <property name="username" value="${batch.jdbc.user}" />  
    <property name="password" value="${batch.jdbc.password}" /> 
    <property name="maxIdle" value="10" />
    <property name="maxActive" value="100" />
    <property name="maxWait" value="10000" />
    <property name="validationQuery" value="select 1" />
    <property name="testOnBorrow" value="false" />
    <property name="testWhileIdle" value="true" />
    <property name="timeBetweenEvictionRunsMillis" value="1200000" />
    <property name="minEvictableIdleTimeMillis" value="1800000" />
    <property name="numTestsPerEvictionRun" value="5" />
    <property name="defaultAutoCommit" value="true" />
</bean>

Мой класс DAO имеет метод, настроенный с

@Transactional(propagation = Propagation.REQUIRES_NEW)

и я перебираю коллекцию операторов SQL, вызывая метод с одним оператором SQL за раз. Обработка внутри метода так же проста, как:

simpleJdbcTemplate.getJdbcOperations().execute(sql);

Я ожидал, что когда метод DAO завершится, я увижу результаты в БД. Однако, похоже, что только когда выполнение задания Spring завершается, результаты становятся доступными в БД.

Я попытался сделать коммит внутри моего метода DAO:

@Transactional(propagation = Propagation.REQUIRES_NEW)
private void executeSingleQuery(String sql) {
    PlatformTransactionManager transactionManager = (PlatformTransactionManager)context.getBean("transactionManager");


    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setPropagationBehavior(Propagation.REQUIRED.ordinal());

    TransactionStatus status = transactionManager.getTransaction(def);

    try {
        // execute your business logic here
        log.info("about to execute SQL query[" + sql + "]");
        simpleJdbcTemplate.getJdbcOperations().execute(sql);

    } catch (Exception e) {
        log.info("SQL query  was not committed due to exception and was marked for rollback");
        transactionManager.rollback(status);
    }

    transactionManager.commit(status);

    if (transactionManager.getTransaction(null).isRollbackOnly() 
            && transactionManager.getTransaction(null).isCompleted()) {
        log.info("SQL query commited!");
    } else {
        log.info("SQL query  was not committed due to: 1) the transaction has been marked for rollback " +
                "2) the transaction has not completed for some reason");
    }

    log.info("the query has completed");
}

Я отладил код Spring и увидел, что транзакция, которую я вызываю из моего метода DAO, выполняется TransactionTemplate (поток достигает строки this.transactionManager.commit(status); и проходит без исключений)

Буду признателен за любой совет, что следует сделать, чтобы метод DAO фиксировался при каждом вызове (коммит после каждого выполняемого оператора SQL).

3 ответа

Решение

Вы не можете использовать частные методы прокси. то есть @Transactional, который у вас есть, не имеет никакого эффекта. Потяните метод к вашему родительскому интерфейсу, и он должен работать. Если у вас не включен параметр proxyTargetClass, что не рекомендуется.

Когда вы звоните executeSingleQuery() из того же класса вы не проходите через прокси, поэтому аннотации транзакций не будут иметь никакого эффекта.

Вы смешиваете декларативные и программные транзакции, по-видимому, вы хотите REQUIRES_NEW чтобы вы могли убрать бессмысленное @Transactional аннотация и использование Propagation.REQUIRES_NEW при настройке вашего DefaultTransactionDefinition,

Кроме того, вы можете захотеть переехать transactionManager.commit(status) внутри try блок, ваш текущий код откатывается, затем пытается зафиксировать, когда Exception происходит.

Мы использовали @Rollback(value = false) аннотации и это решило проблему, с которой вы столкнулись.

Другие вопросы по тегам