Spring事务管理器:回滚不起作用

3
我希望在一个事务块中执行几个插入查询,如果出现任何错误,则所有插入都将回滚。
我正在使用MySQL数据库和Spring TransactionManager。表类型为InnoDB。
我按照此处链接所述的步骤进行了配置。
以下是我的代码(现在只有一个查询)。
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = null;

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

Spring配置文件:

<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>

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

请问有人可以指导我错在哪里吗?


你能展示一下你的数据源配置吗? - fpmoles
@Moles-JWS:我已更新我的问题并添加了数据源设置。希望这能有所帮助。 - DarkKnightFan
2个回答

4

看起来问题在于您的数据源没有设置自动提交关闭。

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

尝试一下。我从未在代理之外使用TransactionManager,所以我不确定直接使用它是否还有其他的注意事项,但我建议您查看AOP事务或方便的AOP代理注释@Transactional,因为这更为常见。


谢谢老兄。这个有用了。但是我还有另一个问题,如果你能在这里回答的话。我能在Java代码中处理这个问题吗,明确设置autoCommit为OFF,执行语句,COMMIT/ROLLBACK,然后再将autoCommit设置为ON。 - DarkKnightFan
当然可以,只需从Spring获取dataSource的句柄,从其连接中可以翻转AutoCommit位,执行代码,然后将其翻转回来并继续进行。我不明白为什么要这样做,但这只是我的观点。 - fpmoles
我知道这不是处理这种情况的最佳方式,但我需要使用事务管理的地方只有一次。因此,我不想更改已经存在并正在使用的全局数据源配置。感谢您的答案。我会尝试一下。 - DarkKnightFan

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的答案后,我现在能够成功回滚。但我希望仅在此方法中处理它,而不更改数据源的全局配置。

我可以在这里以编程方式实现吗?


1
我在想,dmlDataSource.setDefaultAutoCommit(false) 不会影响你的全局数据源吗?当这部分代码运行时,每个模块的所有数据库事务都将自动提交设置为 false。 - Shamim Hafiz - MSFT
1
嗯...你提出了一个很好的观点@ShamimHafiz...我得测试一下...另一个选择是我为这个函数创建一个单独的jdbctemplate实例。这样上述更改就不会对代码的其余部分产生任何影响。 - DarkKnightFan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接