gpt4 book ai didi

使用 r2dbc 的基于 Multi-Tenancy 模式的应用程序

转载 作者:行者123 更新时间:2023-12-04 04:13:55 28 4
gpt4 key购买 nike

我正在开发一个使用 Spring-Webflux + Spring-data-r2dbc 和 r2dbc 驱动程序连接到 Postgresql 数据库的 Multi-Tenancy 响应式(Reactive)应用程序。
Multi-Tenancy 部分是基于模式的:每个租户一个模式。因此,根据上下文(例如用户登录),请求将命中数据库的某个模式。

我正在为如何在 r2dbc 中实现这一点而苦苦挣扎。理想情况下,这将是 Hibernate 处理 MultiTenantConnectionProvider 的方式。 (参见示例 16.3)。

我发现了什么以及到目前为止我做了什么:

  • 可以使用AbstractRoutingConnectionFactory如前所述here .但我被迫按租户/模式创建一个 ConnectionFactory。在我看来,这远非高效/可扩展,我宁愿使用像 r2dbc-pool 这样的连接池
  • 我看了PostgresqlConnectionFactory .这里有趣的是 prepareConnection有电话在 setSchema(connection) :
    private Mono<Void> setSchema(PostgresqlConnection connection) {
    if (this.configuration.getSchema() == null) {
    return Mono.empty();
    }

    return connection.createStatement(String.format("SET SCHEMA '%s'", this.configuration.getSchema()))
    .execute()
    .then();
    }

  • 可能我需要找到一种方法来覆盖它以便从上下文而不是配置中动态获取架构?
  • 否则我可以尝试将请求中的模式指定为表前缀:
        String s = "tenant-1";
    databaseClient.execute("SELECT * FROM \"" + s + "\".\"city\"")
    .as(City.class)
    .fetch()
    .all()

  • 但是我不能再使用 SpringData 或者我需要覆盖每个请求以将租户作为参数传递。

    任何提示/帮助表示赞赏:)

    最佳答案

    我也遇到了这个。

    这是我目前正在做的事情:

  • 将 PostgresqlConnectionConfigurationBuilder 和 PostgresqlConnectionFactory 发布为 Bean:
    @Bean
    public PostgresqlConnectionConfiguration.Builder postgresqlConnectionConfiguration() {
    return PostgresqlConnectionConfiguration.builder()
    .host("localhost")
    .port(5432)
    .applicationName("team-toplist-service")
    .database("db")
    .username("user")
    .password("password");
    }

    @Bean
    @Override
    public PostgresqlConnectionFactory connectionFactory() {
    return new PostgresqlConnectionFactory(postgresqlConnectionConfiguration()
    .build());
    }

  • 这样我以后可以(在我的业务方法中)使用注入(inject)的 PostgresqlConnectionConfigurationBuilder 实例创建一个新的 PostgresqlConnectionFactory - 但是 现在在构建器上也调用了“模式” setter (在从传入的 org.springframework.web.reactive.function.server.ServerRequest 提取租户信息之后,我从路由 bean 传递下来。

    我的数据库模式遵循模式 appname_tenantId,
    所以我们有一个静态配置为“app_name”的“appName”,所以我最终得到了像“app_name_foo_bar123”这样的模式名称

    接下来,我们有一个租户标识符,在我的情况下,它来自一个请求 header ,该 header 保证由位于上游的 apache 服务器设置(传递传入请求的 X-Tenant-Id header ,以便不依赖 URL 来执行租户特定路由)

    所以我的“逻辑”目前看起来有点像这样:
    public Flux<TopTeam> getTopTeams(ServerRequest request) {

    List<String> tenantHeader = request.headers().header("X-Tenant-Id");
    // resolve relevant schema name on the fly
    String schema = (appName+ "_" + tenantHeader.iterator().next()).replace("-", "_");
    System.out.println("Using schema: " + schema);
    // configure connfactory with schema set on the builder
    PostgresqlConnectionFactory cf = new PostgresqlConnectionFactory(postgresqlConnectionConfiguration.schema(schema).build());
    // init new DatabaseClient with tenant specific connection
    DatabaseClient cli = DatabaseClient.create(cf);


    return cli
    .execute("select * from top_teams ").fetch().all()
    .flatMap(map -> {

    ...
    });
    });
    }

    这个逻辑当然可以抽象出来,但是不确定放在哪里,也许可以将它移到 MethodArgumentResolver 中,这样我们就可以注入(inject)一个已经配置的 DatabaseClient

    ps:这只解决了使用DatabaseClient时的 Multi-Tenancy 问题。
    我不确定如何使用 R2dbcRepositories 进行这项工作

    关于使用 r2dbc 的基于 Multi-Tenancy 模式的应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61122270/

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