gpt4 book ai didi

spring-boot - Multi-Tenancy : Managing multiple datasources with Spring Data JPA

转载 作者:行者123 更新时间:2023-12-04 22:40:01 27 4
gpt4 key购买 nike

我需要创建一个可以管理多个数据源的服务。
当应用程序第一次运行应用程序时,这些数据源不一定存在,实际上一个端点会创建新的数据库,我希望能够切换到它们并创建数据。

例如,假设我有 3 个数据库,A、B 和 C,然后我启动应用程序,我使用创建 D 的端点,然后我想使用 D。

那可能吗?

我知道如何切换到其他数据源(如果存在),但我现在看不到任何可以使我的请求成为可能的解决方案。
你有什么想法吗?

谢谢

最佳答案

要使用 Spring Boot 实现 Multi-Tenancy ,我们可以使用 AbstractRoutingDataSource作为基础 数据源 所有“租户数据库”的类。

它有一个抽象方法determineCurrentLookupKey我们必须覆盖。它告诉 AbstractRoutingDataSource它目前必须提供哪个租户数据源才能使用。因为它工作在多线程环境中,所以所选租户的信息应该存储在ThreadLocal中。多变的。
AbstractRoutingDataSource将租户数据源的信息存储在其私有(private) Map<Object, Object> targetDataSources 中.这张 map 的关键是租户标识符 (例如 String 类型)和值 - 租户数据源 .要将我们的租户数据源放入此 map ,我们必须使用其 setter setTargetDataSources .
AbstractRoutingDataSource如果没有我们必须使用方法 setDefaultTargetDataSource(Object defaultTargetDataSource) 设置的“默认”数据源,它将无法工作.

在我们设置租户数据源和默认数据源后,我们必须调用方法 afterPropertiesSet()告诉AbstractRoutingDataSource更新其状态。

所以我们的“MultiTenantManager”类可以是这样的:

@Configuration
public class MultiTenantManager {

private final ThreadLocal<String> currentTenant = new ThreadLocal<>();
private final Map<Object, Object> tenantDataSources = new ConcurrentHashMap<>();
private final DataSourceProperties properties;

private AbstractRoutingDataSource multiTenantDataSource;

public MultiTenantManager(DataSourceProperties properties) {
this.properties = properties;
}

@Bean
public DataSource dataSource() {
multiTenantDataSource = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
return currentTenant.get();
}
};
multiTenantDataSource.setTargetDataSources(tenantDataSources);
multiTenantDataSource.setDefaultTargetDataSource(defaultDataSource());
multiTenantDataSource.afterPropertiesSet();
return multiTenantDataSource;
}

public void addTenant(String tenantId, String url, String username, String password) throws SQLException {

DataSource dataSource = DataSourceBuilder.create()
.driverClassName(properties.getDriverClassName())
.url(url)
.username(username)
.password(password)
.build();

// Check that new connection is 'live'. If not - throw exception
try(Connection c = dataSource.getConnection()) {
tenantDataSources.put(tenantId, dataSource);
multiTenantDataSource.afterPropertiesSet();
}
}

public void setCurrentTenant(String tenantId) {
currentTenant.set(tenantId);
}

private DriverManagerDataSource defaultDataSource() {
DriverManagerDataSource defaultDataSource = new DriverManagerDataSource();
defaultDataSource.setDriverClassName("org.h2.Driver");
defaultDataSource.setUrl("jdbc:h2:mem:default");
defaultDataSource.setUsername("default");
defaultDataSource.setPassword("default");
return defaultDataSource;
}
}

简要说明:
  • map tenantDataSources这是我们放入 setTargetDataSources 的本地租户数据源存储。二传手;
  • DataSourceProperties properties用于从 spring.datasource.driverClassName 获取租户数据库的数据库驱动程序类名称'application.properties'(例如,org.postgresql.Driver);
  • 方法addTenant用于将新租户及其数据源添加到我们的本地租户数据源存储中。 我们可以即时执行此操作 - 感谢方法afterPropertiesSet() ;
  • 方法setCurrentTenant(String tenantId)用于“切换”到给定租户的数据源。我们可以使用这种方法,例如,在 REST Controller 中处理使用数据库的请求时。请求应包含“tenantId”,例如在 X-TenantId 中 header ,我们可以检索并放入此方法;
  • defaultDataSource()使用内存 H2 数据库构建,以避免在工作 SQL 服务器上使用默认数据库。

  • 注:您 必须设置 spring.jpa.hibernate.ddl-auto none 的参数禁用 Hibernate 在数据库模式中进行更改。您必须事先创建租户数据库的架构。

    本类(class)的完整示例以及更多您可以在我的 中找到repo .

    更新

    这个 branch演示了使用专用数据库存储租户数据库属性而不是属性文件的示例(请参阅下面的@MarcoGustavo 问题)。

    关于spring-boot - Multi-Tenancy : Managing multiple datasources with Spring Data JPA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49759672/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com