【问题标题】:Spring TransactionManager - commit does not workSpring TransactionManager - 提交不起作用
【发布时间】:2012-04-10 08:58:03
【问题描述】:

我正在尝试创建基于 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 语句之后提交)。

【问题讨论】:

  • @Transactional 注释负责提交。我想,在您的代码中,您不需要引用事务管理器并明确提交更改。

标签: java jdbc transactions spring-batch transactionmanager


【解决方案1】:

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

【讨论】:

  • 将 DAO 方法更改为 public - 同样的问题
  • 将方法拉到父界面有助于解决这种情况。舒克兰! :)
【解决方案2】:

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

您正在混合声明性事务和程序性事务,大概您想要REQUIRES_NEW,因此您可以在设置DefaultTransactionDefinition 时删除无意义的@Transactional 注释并使用Propagation.REQUIRES_NEW

此外,您可能希望将 transactionManager.commit(status) 移动到 try 块内,您当前的代码回滚,然后在出现 Exception 时尝试提交。

【讨论】:

  • 谢谢,我赞成您的回答,因为它很有帮助(部分内容)。但是我不能接受 2 个答案 - 而 MadheTo 是第一个回答...
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-30
    • 2015-10-15
    • 2022-06-16
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多