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

Rob*_*ans 5 java multi-tenant spring-data spring-data-jpa

我一直在努力让这个工作几天,但似乎我找不到解决方案。这就是为什么我想在这里问它。

精简版

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

@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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

编辑 (07-06-2016)
由于我注意到切换单个事务的数据源不起作用,我将添加一个后续内容。

是否可以为单个用户请求在两个事务之间切换数据源?如果是这样,这样做的正确方法是什么?

长版

在继续之前,我想提一下,我的多租户实现基于此博客提供教程

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

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

@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;
  }

}
Run Code Online (Sandbox Code Playgroud)

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

@Transactional("dynamicTransactionManager")
public Custom getDynamicCustom(String name) {
  ...stuff...
}

@Transactional("defaultTransactionManager")
public Custom getDefaultCustom(String name) {
  ...stuff...
}
Run Code Online (Sandbox Code Playgroud)

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

我希望有人能帮我找到解决方案。
提前致谢。

Kay*_*man 0

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