Spring @Transactional,具有跨多个数据源的事务
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring @Transactional,具有跨多个数据源的事务相关的知识,希望对你有一定的参考价值。
我必须更新两个数据源作为一个事务的一部分。那是 -
- 我在DB1中做了更新。
- 然后,我在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 @Transactional 对服务和非服务方法的不同行为?