Spring @Transactional,具有跨多个数据源的事务

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring @Transactional,具有跨多个数据源的事务相关的知识,希望对你有一定的参考价值。

我必须更新两个数据源作为一个事务的一部分。那是 -

  1. 我在DB1中做了更新。
  2. 然后,我在DB2中进行另一次更新。

如果DB2中的更新失败,我想回滚DB1和DB2以进行回滚。这可以使用@Transactional完成吗?

这是一个示例代码 -

@Transactional(value="db01TransactionManager")
public void updateDb01() {
    Entity01 entity01 = repository01.findOne(1234);
    entity01.setName("Name");
    repository01.save(entity01);

    //Calling method to update DB02
    updateDb02();
}

@Transactional(value="db02TransactionManager")
public void updateDb02() {
    Entity02 entity02 = repository02.findOne(1234);
    entity02.setName("Name");
    repository02.save(entity02);

    //Added this to force a roll back for testing
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

我的问题是,updateDb02中的setRollbackOnly()仅回滚Db01事务。

答案

我已经使用ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html解决了这个问题

Spring Boot配置:

    @Bean(name = "chainedTransactionManager")
    public ChainedTransactionManager transactionManager(@Qualifier("primaryDs") PlatformTransactionManager ds1,
                                                    @Qualifier("secondaryDs") PlatformTransactionManager ds2) {
         return new ChainedTransactionManager(ds1, ds2);
    }

然后你可以按如下方式使用它:

@Transactional(value="chainedTransactionManager")
public void updateDb01() {
    Entity01 entity01 = repository01.findOne(1234);
    entity01.setName("Name");
    repository01.save(entity01);

    //Calling method to update DB02
    updateDb02();
}

public void updateDb02() {
    Entity02 entity02 = repository02.findOne(1234);
    entity02.setName("Name");
    repository02.save(entity02);

    //Added this to force a roll back for testing
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
另一答案

最好的方法是创建第三个方法,将其注释为@Transactional

@Transactional(readOnly = false)
public void updateCommon(){
  upbateDb01();
  upbateDb02();
}

根据spring文档,事务控制在第一个注释出现时开始,因此在这种情况下,当调用updateCommon时,将启动单个事务。更新但如果您使用CrudRepository或类似的东西,这将有效。

如果有多个数据源,您可以尝试使用全局事务管理概念。以下是spring文档中的示例:

@Inject private PlatformTransactionManager txManager; 

TransactionTemplate template  = new TransactionTemplate(this.txManager); 
template.execute( new TransactionCallback<Object>(){ 
  public void doInTransaction(TransactionStatus status){ 
   // work done here will be wrapped by a transaction and committed. 
   // the transaction will be rolled back if 
   // status.setRollbackOnly(true) is called or an exception is thrown 
  } 
});

这里有一个链接:http://spring.io/blog/2011/08/15/configuring-spring-and-jta-without-full-java-ee/我从来没有把它用于我自己,所以我没有深入探讨这个话题。希望它会有所帮助

另一答案

弄清楚了。

这些方法必须位于不同的bean中才能使用不同的事务管理器。

另一答案

我相信你已经定义了如下所示的txns。

@Bean(name="db01TransactionManager") 
@Autowired
DataSourceTransactionManager tm1(@Qualifier ("datasource1") DataSource datasource) {
    DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
    return txm;
}

@Bean(name="db02TransactionManager") 
@Autowired
DataSourceTransactionManager tm2(@Qualifier ("datasource2") DataSource datasource) {
    DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
    return txm;
}

现在最简单的方法是尝试,捕获和回滚两个事务。但是,如果您仍想委托,则可以选择以下选项。

创建自己的并覆盖回滚方法并使用它。

@Bean(name=“allTransactionManager") 
@Autowired
DataSourceTransactionManager tm2(@Qualifier ("datasource1”) DataSource datasource1, @Qualifier ("datasource2") DataSource datasource2) {

    DataSourceTransactionManager txm  = new MyDataSourceTransactionManager(datasource1,datasouce2);
        return txm;
}

并将您自己的事务管理器定义为。

MyDataSourceTransactionManager extends DataSourceTransactionManager{
DataSourceTransactionManager tm1; 
DataSourceTransactionManager tm2; 

MyDataSourceTransactionManager(Datasource ds1,Datasource d2){
  tm1 = new DataSourceTransactionManager(DataSource);
  tm2 =new DataSourceTransactionManager(DataSource);
}
// override and for roll back, rollback for both of tm1 and tm2. Thus all actions are delegated in this class

}

然后在任何想要同步工作的地方使用它。

 @Transactional("allTransactionManager")

所以现在我们有了自己的事务管理器,它能够为两种类型的事务一起回滚或提交。

以上是关于Spring @Transactional,具有跨多个数据源的事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring @Transactional 具有来自不同调用源的不同隔离级别

具有@async超时值的Spring @transactional不起作用

Spring跨越方法的JPA事务

Spring @Transactional 对服务和非服务方法的不同行为?

SpringBoot整合Shiro 涉及跨域和@Cacheable缓存/@Transactional事务注解失效问题

LazyInitializationException 和 @Transactional 不起作用