【问题标题】:Spring Boot: Transaction with two DB, rollback first DB if second DB failsSpring Boot:与两个数据库的事务,如果第二个数据库失败则回滚第一个数据库
【发布时间】:2019-10-10 14:00:31
【问题描述】:

我正在构建一个具有两个数据源的 Spring Boot 应用程序。我需要在 DB1 中进行更新,然后在 DB2 中进行更新。但是如果 DB2 的更新失败,DB1 的更新应该回滚。

我看到a post 遇到同样的问题,但ChainedTransactionManager 实现对我不起作用。

我目前的实现是:

我有 2 个具有不同数据源的 bean,用于事务管理器:

    <bean id="dataSourceTransactionManagerSP" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" primary="true">
        <constructor-arg ref="dataSourceSP"/>
    </bean>

    <bean id="dataSourceTransactionManagerBOL" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSourceBOL"/>
    </bean>

我有两个进行更新的事务方法。出于某种奇怪的原因,@Transactional 注释在任何方法中都不起作用。但到目前为止,这两种方法在其数据源中运行良好。

对于第一个数据库:

    @Override
    public Boolean updateDB1() {
        transactionTemplate.setTransactionManager(dataSourceTransactionManagerSP);
        return transactionTemplate.execute(status -> {
            boolean r1 = repository1.update1();
            boolean r2 = repository1.update2();
            return r1 && r2;
        });
    }

第二个数据库:

    @Override
    public Boolean updateDB2() {
        transactionTemplate.setTransactionManager(dataSourceTransactionManagerBOL);
        return transactionTemplate.execute(status -> {
            boolean r1 = repository2.update1();
            boolean r2 = repository2.update2();
            return r1 && r2;
        });
    }

但现在我需要一个调用updateDB1updateDB2 的方法,如果DB2 失败,DB1 会回滚。

    @Override
    public Boolean updateBoth() {

        return transactionTemplate.execute(status -> {
            boolean r1 = updateDB1();
            boolean r2 = updateDB2();
            return r1 && r2;
        });
    }

我知道这行不通,因为我需要指定 TransactionManager,但这是问题所在,我有两个事务管理器。

【问题讨论】:

    标签: java spring datasource jdbctemplate transactional


    【解决方案1】:

    我认为您应该在相同的方法 updateBoth 中控制回滚 DB1。在 spring Doc 中你可以找到这个例子:

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    
      protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
          updateOperation1();this is your updateDB1()
          updateOperation2();-->this is your updateDB2()
        } catch (SomeBusinessExeption ex) {
          status.setRollbackOnly();
        }
      }
    });
    

    我会让 updateDB2() 启动一些可能被捕获的自定义异常,然后使状态回滚。在这种情况下,假设您想要手动回滚的是 DB1,那么要使用的事务管理器是 dataSourceTransactionManagerSP (DB1)。您可以使用@Transactional("dataSourceTransactionManagerBOL") 控制DB2 的事务

    【讨论】:

    • 谢谢!你能分享一下你在哪里找到这个的 Spring Doc 吗?
    • 您的回答帮助我找到了解决方案:)。最后,我创建了一个仅适用于 DB1 的新事务模板,创建了事务并在其中创建了另一个适用于 DB2 的事务模板。如果 DB2 失败,我会抛出第一个 transactionTemplate 捕获的异常并且回滚工作。非常感谢!
    猜你喜欢
    • 2019-02-09
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    相关资源
    最近更新 更多