【问题标题】:Springboot 2.3.1 dynamically update Jdbc template's schema in Multi-tenant environmentSpring Boot 2.3.1 在多租户环境中动态更新 Jdbc 模板架构
【发布时间】:2020-07-30 17:44:09
【问题描述】:

我的项目在 spring-boot-starter-parent - "1.5.9.RELEASE" 上,我正在将它迁移到 spring-boot-starter-parent - "2.3.1.RELEASE"。

这是一个多租户环境应用程序,其中一个数据库将具有多个模式,并根据租户 ID 在模式之间切换执行。

我已经使用 SimpleNativeJdbcExtractor 实现了这种模式切换,但在最新的 Springboot 版本中,NativeJdbcExtractor 不再可用。

现有实现的代码 sn-p:

 @Bean
@Scope(
        value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
        proxyMode = ScopedProxyMode.TARGET_CLASS)
public JdbcTemplate jdbcTemplate() {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    SimpleNativeJdbcExtractor simpleNativeJdbcExtractor = new SimpleNativeJdbcExtractor() {
        @Override
        public Connection getNativeConnection(Connection con) throws SQLException {
            LOGGER.debug("Set schema for getNativeConnection "+Utilities.getTenantId());
            con.setSchema(Utilities.getTenantId());
            return super.getNativeConnection(con);
        }

        @Override
        public Connection getNativeConnectionFromStatement(Statement stmt) throws SQLException {
            LOGGER.debug("Set schema for getNativeConnectionFromStatement "+Utilities.getTenantId());
            Connection nativeConnectionFromStatement = super.getNativeConnectionFromStatement(stmt);
            nativeConnectionFromStatement.setSchema(Utilities.getTenantId());
            return nativeConnectionFromStatement;
        }
    };

    simpleNativeJdbcExtractor.setNativeConnectionNecessaryForNativeStatements(true);
    simpleNativeJdbcExtractor.setNativeConnectionNecessaryForNativePreparedStatements(true);

    jdbcTemplate.setNativeJdbcExtractor(simpleNativeJdbcExtractor);
    return jdbcTemplate;
}

这里的 Utilities.getTenantId()(存储在 ThreadLocal 中的值)将根据 REST 请求给出架构名称。

问题:

  • NativeJdbcExtractor 的替代方法是什么,以便可以为 JdbcTemplate 动态更改架构?
  • 有没有其他方法,在创建 JdbcTemplate bean 时,我可以根据请求设置架构。

非常感谢任何帮助、代码 sn-p 或解决此问题的指导。

谢谢。

【问题讨论】:

  • * 在 Springboot2 上是否可行? * 我应该摆脱 JdbcTemplate 吗? (需要大量的编码和测试工作)* 我应该停止迁移吗?

标签: java database spring-boot multi-tenant jdbctemplate


【解决方案1】:

没有必要摆脱JdbcTemplateNativeJdbcExtractorremoved in Spring Framework 5,因为 JDBC 4 不需要它。

您应该使用对connection.unwrap(Class) 的调用替换您对NativeJdbcExtractor 的使用。该方法由Connection继承自JDBC的Wrapper

您可能还想考虑使用AbstractRoutingDataSource,它旨在根据查找键将连接请求路由到不同的底层数据源。

【讨论】:

  • 它是否允许我在数据源下的不同模式之间切换。?因为我不是在寻找不同数据源之间的切换。
【解决方案2】:

当我在调试模式下运行应用程序时,我看到 Spring 选择了 Hikari 数据源。

我不得不拦截 getConnection 调用并更新架构。

所以我做了下面的事情,

创建了一个扩展 HikariDataSource 的自定义类

public class CustomHikariDataSource extends HikariDataSource {
@Override
public Connection getConnection() throws SQLException {

    Connection connection =  super.getConnection();
    connection.setSchema(Utilities.getTenantId());
    return connection;
}
}

然后在配置类中,我为我的 CustomHikariDataSource 类创建了 bean。

 @Bean
public DataSource customDataSource(DataSourceProperties properties) {

    final CustomHikariDataSource dataSource = (CustomHikariDataSource) properties
            .initializeDataSourceBuilder().type(CustomHikariDataSource.class).build();
    if (properties.getName() != null) {
        dataSource.setPoolName(properties.getName());
    }
    return dataSource;
}

JdbcTemplate bean 将使用它。

 @Bean
@Scope(
        value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
        proxyMode = ScopedProxyMode.TARGET_CLASS)
public JdbcTemplate jdbcTemplate() throws SQLException {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    return jdbcTemplate;
}

使用这种方法,我将只创建一次 DataSource bean,并且对于每个 JdbcTemplate 访问,将在运行时更新正确的架构。

【讨论】:

    猜你喜欢
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 2019-06-23
    • 2015-01-10
    • 2018-09-20
    相关资源
    最近更新 更多