7

我正在尝试创建基于 Spring 的解决方案,用于在 MySQL 5.5 服务器上运行批量 SQL 查询。“查询”是指任何可以编译的 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 语句之后提交)。

4

3 回答 3

8

您不能代理私有方法。即你在这里的@Transactional 没有效果。将该方法拉到您的父界面,它应该可以工作。除非您启用了不推荐的 proxyTargetClass 设置。

于 2012-04-10T09:07:59.033 回答
3

当您executeSingleQuery()从同一类中调用您时,您不会通过代理,因此事务注释将无效。

您正在混合声明性和程序化事务,大概是您想要REQUIRES_NEW的,这样您就可以删除无意义的@Transactional注释并Propagation.REQUIRES_NEW在设置DefaultTransactionDefinition.

此外,您可能想transactionManager.commit(status)try块内移动,您当前的代码回滚,然后在Exception发生时尝试提交。

于 2012-04-10T09:45:21.403 回答
0

我们使用了@Rollback(value = false)注释并解决了您面临的问题。

于 2015-11-20T22:11:07.113 回答