Spring Boot 2.3.1 在多租户环境中动态更新 Jdbc 模板架构
Springboot 2.3.1 dynamically update Jdbc template's schema in Multi-tenant environment
我的项目在 spring-boot-starter-parent - "1.5.9.RELEASE" 上,我正在将它迁移到 spring-boot-starter-parent - " 2.3.1.RELEASE".
这是一个多租户环境应用程序,其中一个数据库将有多个模式,并且根据租户ID,在模式之间切换执行。
我已经使用 SimpleNativeJdbcExtractor 实现了这种模式切换,但是在最新的 Springboot 版本中 NativeJdbcExtractor 不再可用。
现有实现的代码片段:
@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 时我可以根据请求设置架构。
非常感谢解决此问题的任何帮助、代码片段或指导。
谢谢。
没有必要摆脱 JdbcTemplate
。 NativeJdbcExtractor
是 removed in Spring Framework 5 因为 JDBC 不需要它 4.
您应该将 NativeJdbcExtractor
的用法替换为对 connection.unwrap(Class)
的调用。该方法由Connection
继承自JDBC的Wrapper
。
您可能还想考虑使用 AbstractRoutingDataSource
,它旨在根据查找键将连接请求路由到不同的基础数据源。
当我 运行 处于调试模式的应用程序时,我看到 Spring 正在选择 Hikari 数据源。
我不得不拦截 getConnection 调用并更新架构。
所以我做了类似下面的事情,
创建了一个扩展 HikariDataSource
的自定义 class
public class CustomHikariDataSource extends HikariDataSource {
@Override
public Connection getConnection() throws SQLException {
Connection connection = super.getConnection();
connection.setSchema(Utilities.getTenantId());
return connection;
}
}
然后在配置 class 中,我为我的 CustomHikariDataSource class 创建了 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 访问,将在运行时更新正确的架构。
我的项目在 spring-boot-starter-parent - "1.5.9.RELEASE" 上,我正在将它迁移到 spring-boot-starter-parent - " 2.3.1.RELEASE".
这是一个多租户环境应用程序,其中一个数据库将有多个模式,并且根据租户ID,在模式之间切换执行。
我已经使用 SimpleNativeJdbcExtractor 实现了这种模式切换,但是在最新的 Springboot 版本中 NativeJdbcExtractor 不再可用。
现有实现的代码片段:
@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 时我可以根据请求设置架构。
非常感谢解决此问题的任何帮助、代码片段或指导。
谢谢。
没有必要摆脱 JdbcTemplate
。 NativeJdbcExtractor
是 removed in Spring Framework 5 因为 JDBC 不需要它 4.
您应该将 NativeJdbcExtractor
的用法替换为对 connection.unwrap(Class)
的调用。该方法由Connection
继承自JDBC的Wrapper
。
您可能还想考虑使用 AbstractRoutingDataSource
,它旨在根据查找键将连接请求路由到不同的基础数据源。
当我 运行 处于调试模式的应用程序时,我看到 Spring 正在选择 Hikari 数据源。
我不得不拦截 getConnection 调用并更新架构。
所以我做了类似下面的事情,
创建了一个扩展 HikariDataSource
的自定义 classpublic class CustomHikariDataSource extends HikariDataSource {
@Override
public Connection getConnection() throws SQLException {
Connection connection = super.getConnection();
connection.setSchema(Utilities.getTenantId());
return connection;
}
}
然后在配置 class 中,我为我的 CustomHikariDataSource class 创建了 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 访问,将在运行时更新正确的架构。