首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用多租户实现在单个事务期间切换数据源

使用多租户实现在单个事务期间切换数据源
EN

Stack Overflow用户
提问于 2016-06-07 08:38:03
回答 3查看 2.2K关注 0票数 5

几天来,我一直在努力工作,但似乎找不到解决办法。所以我才想在这里问。

短版

我有一个多租户实现,它与Spring、Spring和Hibernate一起工作。这就像一种魅力。但是现在我想实现一个功能,在单个事务期间切换数据库(数据源)。例如,我在服务类中使用类似的代码。

代码语言:javascript
复制
@Autowired
private CustomRepository customRepository;

@Autorwired
private CustomTenantIdentifierResolver customResolver;

@Transactional
public Custom getCustom(String name) {

  // Set the datasource to "one";
  this.customResolver.setIdentifier("one");
  Custom result = this.customRepository.findOneByName(name);

  //If the result is null, switch datasource to default and try again
  this.customResolver.setIdentifier("default");
  result = this.customRepository.findOneByName(name);

  return result;
}

问题是,我的数据源没有切换。对于第二个请求,它使用相同的源。我想我在这里做了严重的错事。

在单个事务期间切换数据源的正确方法是什么?

编辑(07-06-2016)

由于我注意到将数据源切换到单个事务是行不通的,所以我将添加后续内容。

是否有可能为单个用户请求在两个事务之间切换数据源?如果是的话,怎样才是正确的方法呢?

长版本

在继续之前,我想提到我的多租户实现是基于本博客提供的教程的。

现在,我的目标是在动态数据源(由自定义标识符选择)找不到结果时使用默认数据源作为后盾。所有这些都需要在一个用户请求中完成。它在解决方案中使用单个或多个事务注释方法没有什么区别。

到目前为止,我尝试了几种方法,其中一种是上面描述的,另一种包括使用多个事务管理器。该实现使用一个配置文件来创建两个事务管理器bean,每个事务管理器bean都是不同的数据源。

代码语言:javascript
复制
@Configuration
@EnableTransactionManagement
public class TransactionConfig {

  @Autowired
  private EntityManagerFactory entityManagerFactory;

  @Autowired
  private DataSourceProvider dataSourceProvider;

  @Bean(name = "defaultTransactionManager")
  public PlatformTransactionManager defaultTransactionManager() {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
    jpaTransactionManager.setDataSource(dataSourceProvider.getDefaultDataSource());
    jpaTransactionManager.afterPropertiesSet();
    return jpaTransactionManager;
  }

  @Bean(name = "dynamicTransactionManager")
  public PlatformTransactionManager dynamicTransactionManager() {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
    jpaTransactionManager.afterPropertiesSet();
    return jpaTransactionManager;
  }

}

接下来,我将服务方法拆分为两个单独的方法,并添加了@Transactional注释,包括正确的bean名称。

代码语言:javascript
复制
@Transactional("dynamicTransactionManager")
public Custom getDynamicCustom(String name) {
  ...stuff...
}

@Transactional("defaultTransactionManager")
public Custom getDefaultCustom(String name) {
  ...stuff...
}

但是这并没有什么区别,第一个数据源仍然用于第二个方法调用(它应该使用默认的事务管理器)。

我希望有人能帮我找到解决办法。

提前谢谢。

EN

回答 3

Stack Overflow用户

发布于 2017-03-16 02:42:47

Spring提供了一个名为AbstractRoutingDatasource.的DataSource变体。它可以用来代替标准的DataSource实现,并允许一种机制来确定在运行时对每个操作使用哪个具体的DataSource。您所需要做的就是扩展它,并提供一个抽象determineCurrentLookupKey方法的实现。

请记住,每当determineCurrentLookupKey请求连接时,都会调用TransactionsManager方法。因此,如果要切换DataSource,只需打开新事务即可。

你可以在这里找到例子,http://fedulov.website/2015/10/14/dynamic-datasource-routing-with-spring/

票数 2
EN

Stack Overflow用户

发布于 2016-06-07 08:46:46

您不能只将事务转移到另一个数据源。虽然存在分布式(或XA)事务的概念,但它由单独的事务(在单独的数据源中)组成,这些事务被视为单个(分布式)事务的一部分。

票数 0
EN

Stack Overflow用户

发布于 2016-06-07 08:49:58

我不知道这是否可能,但我认为您应该尽量避免在事务期间切换源,原因如下:

如果在第二个请求期间发生错误,您将希望回滚整个事务,这意味着切换回原来的源。为了能够做到这一点,您将需要保持到该旧源的开放连接:当事务完成后,您将需要确认事务到该旧源。

我建议你重新考虑你是否真的想要这样做,如果有可能的话,不要考虑这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37674427

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档