首页 > 解决方案 > Spring boot multitenancy ,其中一个租户连接到多个模式

问题描述

我正在创建一个 Spring Boot 应用程序,它应该支持多租户、单独的数据库方法。每个租户都将使用多个架构,并且将从某个配置文件动态加载。租户和模式将是这样的,

租户 1:

url : dbc:mysql://dns1/abc_schema
username : sa
password : sa

url : dbc:mysql://dns1/pqr_schema
username : sa
password : sa

url : dbc:mysql://dns1/xyz_schema
username : sa
password : sa

租户 2:

url : dbc:mysql://dns2/abc_schema
username : sa
password : sa

url : dbc:mysql://dns2/pqr_schema
username : sa
password : sa

url : dbc:mysql://dns2/xyz_schema
username : sa
password : sa

目前它是一个单租户应用程序,其中所有 3 个模式都在 application.properties 中提到。所有数据库实例具有相同的模式名称,但在不同的数据库实例中。现在,有 3 个带有 @ 配置的单独配置文件用于在应用程序启动时加载表。

我正在将此应用程序转换为多租户应用程序。使用具有单个架构的租户实现多租户应用程序的步骤很清楚,但我有多个租户架构。所以,问题是在实现 AbstractDataSourceBasedMultiTenantConnectionProviderImpl类时,selectDataSource()函数返回单个数据源。但是如何传递其中的多个模式呢?

@Override
    protected DataSource selectDataSource(String tenantIdentifier) {
        if (isInitialLoad) {
            isInitialLoad = false;
            TenantDataSource tenantDataSource = context.getBean(TenantDataSource.class);
            map.putAll(tenantDataSource.getAll());
        }
        return map.get(tenantIdentifier);
    } 

提前致谢, 谢尔茨

标签: mysqlspringhibernatespring-boot

解决方案


这只是给出的方法并不完全是解决方案

如下所示定义路由器,然后您可以在配置中设置

public class ClientDataSourceRouter
  extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return ClientDatabaseContextHolder.getClientDatabase();
    }
}

我们需要一个上下文映射到 DataSource 对象来配置我们的 AbstractRoutingDataSource。如果没有设置上下文,我们还可以指定要使用的默认 DataSource。

我们使用的数据源可以来自任何地方,但通常会在运行时创建或使用 JNDI 查找:

@Configuration 公共类 RoutingTestConfiguration {

@Bean
public DataSource clientDatasource() {
    Map<Object, Object> targetDataSources = new HashMap<>();
    DataSource clientADatasource = clientADatasource();
    DataSource clientBDatasource = clientBDatasource();
    targetDataSources.put(ClientDatabase.CLIENT_A, 
      clientADatasource);
    targetDataSources.put(ClientDatabase.CLIENT_B, 
      clientBDatasource);

    ClientDataSourceRouter clientRoutingDatasource 
      = new ClientDataSourceRouter();
    clientRoutingDatasource.setTargetDataSources(targetDataSources);
    clientRoutingDatasource.setDefaultTargetDataSource(clientADatasource);
    return clientRoutingDatasource;
}

// ...

}

查看更多信息 - baeldung

另一种解决方案定义如下

多租户模型 有几种模型可以在应用程序中实现多租户:

  • 每个租户的数据库 每个租户都有自己的数据库,并且与其他租户隔离。
  • 共享数据库,独立架构(这就是我们要找的)

所有租户共享一个数据库,但有自己的数据库模式和自己的表。

  • Shared Database, Shared Schema 所有租户共享一个数据库和表。每个表都有一个带有租户标识符的列,它显示了该行的所有者。

例子 :

@Bean
    public DataSource dataSource() {

        AbstractRoutingDataSource dataSource = new TenantAwareRoutingSource();

        Map<Object,Object> targetDataSources = new HashMap<>();

        targetDataSources.put("TenantOne", tenantOne());
        targetDataSources.put("TenantTwo", tenantTwo());

        dataSource.setTargetDataSources(targetDataSources);

        dataSource.afterPropertiesSet();

        return dataSource;
    }

    public DataSource tenantOne() {

        HikariDataSource dataSource = new HikariDataSource();

        dataSource.setInitializationFailTimeout(0);
        dataSource.setMaximumPoolSize(5);
        dataSource.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");
        dataSource.addDataSourceProperty("url", "jdbc:postgresql://127.0.0.1:5432/sampledb");
        dataSource.addDataSourceProperty("user", "philipp");
        dataSource.addDataSourceProperty("password", "test_pwd");
 **we need to find datasource.setschema is exist or not**
        return dataSource;
    }

    public DataSource tenantTwo() {

        HikariDataSource dataSource = new HikariDataSource();

        dataSource.setInitializationFailTimeout(0);
        dataSource.setMaximumPoolSize(5);
        dataSource.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");
        dataSource.addDataSourceProperty("url", "jdbc:postgresql://127.0.0.1:5432/sampledb1");
        dataSource.addDataSourceProperty("user", "philipp");
        dataSource.addDataSourceProperty("password", "test_pwd");
** we need to find datasource.setschema is exist or not**
        return dataSource;
    }

或者只有一个选项也存在

租户一

spring.datasource.first.url=jdbc:postgresql://my_url:my_port/my_other_stuff
spring.datasource.first.username=my_user_name
spring.datasource.first.password=my_password
spring.datasource.first.driver-class-name=org.postgresql.Driver
spring.datasource.first.schema=A

租户二

spring.source.second.url=jdbc:postgresql://my_url:my_port/my_other_stuff
spring.source.second.username=my_user_name
spring.source.second.password=my_password
spring.source.second.driver-class-name=org.postgresql.Driver
spring.source.second.schema = B

然后为每个创建 PropertySource 类,然后它将由 spring 设置,之后您可以使用它们

 @ConfigurationProperties(prefix = "datasource.first")
@Bean
@Primary
public DataSource dataSource() {
    return DataSourceBuilder
        .create()
        .build();
}

还要检查此链接 在此处输入链接描述


推荐阅读