java Spring TransactionManager - 提交不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10085771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:33:04  来源:igfitidea点击:

Spring TransactionManager - commit does not work

javajdbctransactionsspring-batchtransactionmanager

提问by aviad

I am trying to create Spring-based solution for running batch of SQL queries on MySQL 5.5 server. By "query" I mean any SQL statement that compiles, so the SQL batch job can contain for example several CREATE TABLE, DELETE and then INSERT statements.

我正在尝试创建基于 Spring 的解决方案,用于在 MySQL 5.5 服务器上运行批处理 SQL 查询。“查询”是指任何可编译的 SQL 语句,因此 SQL 批处理作业可以包含例如多个 CREATE TABLE、DELETE 和 INSERT 语句。

I am using Spring Batchfor this purpose.

为此,我正在使用Spring Batch

I have transactionManagerconfigured as follows.

transactionManager配置如下。

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

and the dataSource:

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>

My DAO class has the method configured with

我的 DAO 类的方法配置为

@Transactional(propagation = Propagation.REQUIRES_NEW)

and I loop over a collection of the SQL statements calling the method with single SQL statement a time. The processing inside the method is as simple as:

并且我一次循环使用单个 SQL 语句调用该方法的 SQL 语句的集合。方法内部的处理很简单:

simpleJdbcTemplate.getJdbcOperations().execute(sql);

I expected that when the DAO method completes, I would see the results in the DB. However, it seems like only when the Spring job execution completes the results become available in the DB.

我希望当 DAO 方法完成时,我会在 DB 中看到结果。但是,似乎只有当 Spring 作业执行完成时,结果才会在数据库中可用。

I tried to do the commit inside my DAO method:

我尝试在我的 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");
}

I debugged the Spring code and saw that the commit I call from my DAO method is executed by TransactionTemplate (the flow reaches the line this.transactionManager.commit(status);and passes without exceptions)

我调试了 Spring 代码,看到我从我的 DAO 方法调用的 commit 是由 TransactionTemplate 执行的(流程到达线路this.transactionManager.commit(status);,无异常通过)

I would appreciate any advice what should be done in order to make the DAO method to commit on every call (commit after every SQL statement it executes).

我很感激任何建议,为了使 DAO 方法在每次调用时提交(在它执行的每个 SQL 语句之后提交)应该做什么。

回答by MahdeTo

You cannot proxy private methods. i.e. The @Transactional you have here has no effect. Pull the method to your parent interface and it should work. Unless you have the proxyTargetClass setting enabled which is not recommended.

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

回答by samlewis

When you call your executeSingleQuery()from within the same class you are not going via the proxy so the transactional annotation will have no effect.

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

You are mixing declarative and programmatic transactions, Presumably you want REQUIRES_NEWso you could remove the pointless @Transactionalannotation and use Propagation.REQUIRES_NEWwhen setting up your DefaultTransactionDefinition.

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

Also, you might want to move transactionManager.commit(status)inside the tryblock, your current code rolls back, then attempts a commit when an Exceptionoccurs.

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

回答by John Harris

We used the @Rollback(value = false)annotation and that fixed the issue you are facing.

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