当前位置: 首页 > 面试题库 >

多租户:使用Spring Data JPA管理多个数据源

燕琛
2023-03-14
问题内容

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

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

那可能吗?

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

谢谢


问题答案:

为了使用Spring
Boot实现多租户,我们可以将AbstractRoutingDataSource用作所有“
租户数据库 ”的基础 DataSource 类。 __

它有一个抽象方法determineCurrentLookupKey我们必须重写。它告诉您当前必须使用AbstractRoutingDataSource哪个租户数据源。因为它在多线程环境中工作,所以所选租户的信息应存储在ThreadLocal变量中。

AbstractRoutingDataSource租户数据源的信息存储在其private中Map<Object, Object> targetDataSources。该映射的键是 租户标识符 (例如String类型)和值- 租户数据源
。要将租户数据源放入此地图,我们必须使用其setter setTargetDataSources

如果AbstractRoutingDataSource没有必须使用method设置的“默认”数据源,则无法使用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;
    }
}

简要说明:

  • 映射tenantDataSources它是我们放置到setTargetDataSources设置程序中的本地租户数据源存储;

  • DataSourceProperties properties用于从spring.datasource.driverClassName‘application.properties’ 的租户数据库获取数据库驱动程序类名称(例如org.postgresql.Driver);

  • 方法addTenant用于将新的租户及其数据源添加到我们的本地租户数据源存储中。有了这种方法, 我们可以快速做到afterPropertiesSet() ;

  • 方法setCurrentTenant(String tenantId)用于“切换”到给定租户的数据源。例如,在处理使用数据库的请求时,我们可以在REST控制器中使用此方法。该请求应包含“ tenantId”,例如在X-TenantId标头中,我们可以检索并放入此方法;

  • defaultDataSource() 是使用内存中的H2数据库构建的,以避免在运行的SQL Server上使用默认数据库。

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

此类的完整示例,您可以在我的 仓库中
找到更多示例。

更新

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



 类似资料:
  • 我们正在开发一个多租户应用程序。在体系结构方面,我们为业务逻辑设计了共享中间层,为数据持久性设计了每个租户一个数据库。也就是说,业务层将与每个租户的数据库服务器建立一组连接(连接池)。这意味着应用程序为每个租户维护单独的连接池。如果我们预计约有5000个租户,那么这个解决方案需要高资源利用率(每个租户的应用服务器和数据库服务器之间的连接),这会导致性能问题。 我们已经通过保持公共连接池解决了这个问

  • 我们现在有点问题:因为用户 tenant2 有 Administration:Security 权限,所以他可以访问用户和角色权限对话框。因此,他可以使用权限 UI 给自己授予 Administration:Tenants 权限。 Serenity 扫描程序集的特性,比如 ReadPermission、WritePermission、PageAuthorize、ServiceAuthorize 等

  • 2.1 ABPZero - 多租户管理 2.1.1 关于多租户 强烈建议阅读这个文件前阅读多租户文档。 2.1.2 启用多租户 ASP.NET Boilerplate和module-zero可以运行多租户或单租户模式。多租户默认为禁用。我们可以在我们的模块PreInitialize方法启用它,使之如下所示: [DependsOn(typeof(AbpZeroCoreModule))] public

  • 我正在将当前的应用程序迁移到多租户体系结构。由于只有一个代码库,我需要解决多个租户的问题。我使用的是单数据库、多模式的方法。每个租户将被分配一个单独的模式,其中元数据保存在默认模式中。 应用程序是用ASP构建的。NET MVC。我使用Dapper连接到我的SQL Server。我有50个函数,使用直接查询和存储过程调用数据库。当为每个租户初始化dapper时,是否有任何方法可以在不改变函数的情况下

  • 我认为为每个租户创建一个Redis实例是一个很好的解决方案。 我有一个包含租户id和Redisendpoint的映射,这是专用于这个租户的。 地图数据如下所示:

  • 是否可以将Spring Boot配置为使用MultiTenantConnectionProvider,以便我的系统的每个客户端都连接到自己的私有数据库? 具体来说,我希望使用内置的hibernate支持多租户: http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html_single/#d5e4561 这是我想要的配置的一个例子,但我不知