【问题标题】:Spring Transaction Manager: Rollback doesnt workSpring 事务管理器:回滚不起作用
【发布时间】:2013-04-19 10:18:27
【问题描述】:

我希望在事务块中执行一些插入查询,如果有任何错误,所有插入都将回滚。

我为此使用MySQL 数据库和Spring TransactionManager。 表格类型也是InnoDB

我已经按照here提到的步骤完成了我的配置。

以下是我的代码(目前只有一个查询)

TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = null;

status = transactionManager.getTransaction(def);
jdbcTemplate.execute(sqlInsertQuery);
transactionManager.rollback(status);

Spring 配置 xml:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

数据源配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="initialSize" value="${jdbc.initialSize}" />
    <property name="maxActive" value="${jdbc.maxActive}" />
    <property name="minIdle" value="${jdbc.minIdle}" />
    <property name="maxIdle" value="${jdbc.maxIdle}" />
    <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
    <property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
    <property name="testOnReturn" value="${jdbc.testOnReturn}" />
    <property name="validationQuery" value="${jdbc.validationQuery}" />
    <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
    <!--<property name="removeAbandoned" value="true"/> <property name="removeAbandonedTimeout" 
        value="10"/> <property name="logAbandoned" value="false"/> -->
    <property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}" />
</bean>

这段代码运行良好,记录被插入。 但是回滚不起作用!它执行回滚语句没有任何错误但没有效果。

谁能指导我哪里出错了?

【问题讨论】:

  • 你能显示你的数据源配置吗?
  • @Moles-JWS:我已经用数据源设置更新了我的问题。希望这会有所帮助

标签: spring transactions spring-transactions transactionmanager


【解决方案1】:

编辑:

我终于能够通过执行以下操作来解决这个问题:

dmlDataSource.setDefaultAutoCommit(false); //set autocommit to false explicitly.
Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
                public Object doInTransaction(TransactionStatus ts) {
                    try {
                        dmlJdbcTemplate.execute(sqlInsertQuery);
                        ts.setRollbackOnly();
                        dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true    
                        return null;
                    } catch (Exception e) {
                        ts.setRollbackOnly();
                        LOGGER.error(e);
                        dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true    
                        return e;
                    }
                }
            });

我现在没有使用事务管理器。使用 trasactionTemplate 并执行以下操作:

Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
                public Object doInTransaction(TransactionStatus ts) {
                    try {
                        dmlJdbcTemplate.execute(sqlInsertQuery);
                        ts.setRollbackOnly();                           
                        return null;
                    } catch (Exception e) {
                        ts.setRollbackOnly();
                        LOGGER.error(e);
                        return e;
                    }
                }
            });

使用@Moles-JWS 的答案后,我现在可以成功回滚。但我只想在这种方法中处理这个问题,而不是更改数据源的全局配置。

我可以在这里编程吗?

【讨论】:

  • 我只是在想,不会 dmlDataSource.setDefaultAutoCommit(false);影响您的全局数据源,当这部分运行时,每个模块中的所有数据库事务都将自动提交设置为 false。
  • hmmm....您提出了一个很好的观点@ShamimHafiz ...我将不得不测试一次...另一种选择是我专门为此功能创建一个单独的 jdbctemplate 实例。这样上面的改动就不会对剩下的代码产生任何影响了。
【解决方案2】:

问题似乎是您的数据源未设置为关闭自动提交。

<property name="defaultAutoCommit" value="false"/>

试试看。我从未在代理之外使用过 TransactionManager,所以我不确定是否有任何其他问题直接像这样使用它,但我建议您查看 AOP 事务或方便的 AOP 代理注释 @Transactional,因为它更常见.

【讨论】:

  • 谢谢伙计。这是有效的。但我还有一个问题,如果你能在这里回答。我可以在 java 代码中处理这个问题吗,其中我明确地将 autoCommit 设置为 OFF,执行语句 COMMIT/ROLLBACK,然后再次将 autoCommit 设置为 ON。
  • 当然可以,只需从 Spring 获取数据源的句柄,从它的连接中,您可以翻转 AutoCommit 位,执行代码,然后将其翻转并继续。我不知道你为什么要这样做,但这只是我的观点。
  • 好吧,我知道这不是处理这种情况的最佳方法,但我需要使用事务管理的地方是一次性的。为此,我不想更改已经到位并正在使用的全局数据源配置。感谢您的回答。会试试看。
猜你喜欢
  • 1970-01-01
  • 2018-12-30
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 2020-08-06
  • 2016-11-07
相关资源
最近更新 更多