【问题标题】:How to use multiple datasources types with the same repositories?如何在相同的存储库中使用多个数据源类型?
【发布时间】:2016-01-10 04:11:11
【问题描述】:

我创建了一个多租户逻辑,并将租户编号存储在 ThreadLocal 中。当数据库属于同一类型(方言)时,一切都很好。在 Spring Boot 初始化期间,JPA 存储库(其 SQL 查询)使用第一个(和默认)数据源进行初始化。

但是,当我配置了例如 Oracle 和 Postgres 数据库时,spring boot 仍然尝试使用第一个租户数据源的方言进行查询,这是一个相当大的问题,因为数据库类型的方言不同。

这将创建租户类型的数据源。如果租户未知(在启动期间),它将采用租户 1。

@Bean
public DataSource dataSource() throws SQLException {
    String tenant1 = "tenant-1";
    String tenant2 = "tenant-2";

    CustomRoutingDataSource customRoutingDataSource = new CustomRoutingDataSource();

    final DataSource tenant1DataSource = createDataSourceForTenant(tenant1);
    final DataSource tenant2DataSource = createDataSourceForTenant(tenant2);

    HashMap<Object, Object> targetDataSources = new HashMap<>();
    targetDataSources.put(tenant1.toUpperCase(), tenant1DataSource);
    targetDataSources.put(tenant2.toUpperCase(), tenant2DataSource);

    customRoutingDataSource.setTargetDataSources(targetDataSources);
    return customRoutingDataSource;
}

这将静态创建数据源 - 稍后当我解决问题时将被从 JNDI 源中动态提取替换:

private DataSource createDataSourceForTenant(String tenant) throws SQLException {
    final DriverManagerDataSource dataSource = new DriverManagerDataSource();

    final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setPackagesToScan(new String[]{"entities"});

    if (tenant.equalsIgnoreCase("tenant-1")) {
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://localhost:5433/importservices");
        dataSource.setUsername("test");
        dataSource.setPassword("test");

        factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factoryBean.afterPropertiesSet();
    }

    if (tenant.equalsIgnoreCase("tenant-2")) {
        dataSource.setDriverClassName("org.hibernate.dialect.Oracle10gDialect");
        dataSource.setUrl("jdbc:oracle:thin:@//oracle11:1521/deviso");
        dataSource.setUsername("test");
        dataSource.setPassword("test");

        factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factoryBean.afterPropertiesSet();
    }

    factoryBean.destroy();
    return dataSource;
}

自定义数据库路由。当租户不可用时(启动期间),getTenant 返回默认值 (1)。

public class CustomRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return "TENANT-"+TenantThreadLocal.getTenant();
    }

}

现在,如果我的默认租户 = 1,spring boot 会在启动时初始化并为实体创建特定于 PostgreSQL 的查询。如果我在运行时以租户 2(Oracle 方言)的身份访问它,我会得到:

java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended

因为 Spring JPA 已经使用 PostgreSQL 方言初始化了 JPA 存储库。所以可能性是:

1) 每个租户多个 EntityManagers - 不太舒服,因为租户是动态管理的
2) 休眠中的多租户支持 - 实际上我不能这样做开始工作,因为 jadira 框架在多租户支持方面存在一些问题,并且在 2 周之前仍未修复并等待fix
3) ??

【问题讨论】:

    标签: java hibernate jpa spring-boot


    【解决方案1】:

    (刚刚发布的)Jadira 5.0.0.GA 有一些变化,可以与多租户部署共存。免责声明:我维护 Jadira。

    【讨论】:

      猜你喜欢
      • 2017-12-21
      • 2018-10-12
      • 1970-01-01
      • 2018-07-18
      • 2019-04-17
      • 2012-02-11
      • 2015-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多