我正在使用Spring Boot和Spring-data-Jpa。我在application.properties文件中设置数据源URL,用户名和密码。它非常适合一个数据库连接,现在我的数据库项目结构面临一个问题,该项目基于特定用户,他自己的数据库需要连接并将结果连接到特定用户数据库,我可以使用抽象数据源来实现这一点,在配置级别使用DataSourceBuilder(这是我一次可以动态更改数据源),但是每次控制器命中时我都需要更改数据源。
这是一些application.properties的代码,我已经使用autowire注入了数据源。
我使用的抽象数据源仅限于静态客户端,但是在我的结构中,“客户端数据库”一直在增长,因此对我没有用
spring.datasource.url=jdbc:sqlserver://test-datbase:1433;dbName1
spring.datasource.username=userName
spring.datasource.password=Password
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
需要代码或方法,每次点击控制器时我都可以更改数据库连接
注意:我只需要更改数据库,方言和其他所有内容即可。
答案 0 :(得分:1)
是的,我们可以使用占位符来做到这一点。在环境变量中设置-DdbName1=YOUR_DB_NAME
。例如:
spring.datasource.url=jdbc:sqlserver://test-datbase:1433;${dbName1}
spring.datasource.username=userName
spring.datasource.password=Password
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
答案 1 :(得分:0)
这是我解决此类问题的方法: 您可以创建2个单独的数据源。为它们创建限定符,并将两者都注入到您的控制器中。 然后在端点中编写逻辑,该逻辑将选择源之一来保存信息。
以下是向项目添加额外数据源的方法:
答案 2 :(得分:0)
我认为在这种情况下使用Wildfly是一个好主意。在Wildfly,您可以使用设置更改连接的数据库。
我的解决方案: enter link description here
,并且在选择数据库时请编写自己的PersistenceConfiguration类 enter link description here
如果您想使用Java代码中的方法动态选择基础
答案 3 :(得分:0)
借助下面的链接,我可以在服务器启动时设置多个数据源
https://fizzylogic.nl/2016/01/24/make-your-spring-boot-application-multi-tenant-aware-in-2-steps/
但是我想删除如下配置注释,并使用如下方法设置租户,但是通过此方法我无法连接到数据库。
public class MultitenantConfiguration {
@Bean
@ConfigurationProperties(
prefix = "spring.datasource"
)
public DataSource dataSource(ArrayList<String> names) {
Map<Object,Object> resolvedDataSources = new HashMap<>();
for(String dbName: names) {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader());
dataSourceBuilder.driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
.url("jdbc:sqlserver://abc.server;databaseName="+dbName+"")
.username("userName")
.password("Password");
resolvedDataSources.put(dbName, dataSourceBuilder.build());
}
MultitenantDataSource dataSource = new MultitenantDataSource();
dataSource.setDefaultTargetDataSource(defaultDataSource());
dataSource.setTargetDataSources(resolvedDataSources);
dataSource.afterPropertiesSet();
return dataSource;
}
/**
* Creates the default data source for the application
* @return
*/
private DataSource defaultDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader())
.driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
.url("jdbc:abc.server;databaseName=test")
.username("UserName")
.password("Password");
return dataSourceBuilder.build();
}
}
答案 4 :(得分:0)
我已经完成了一个项目,可以使用您的特定changeSets创建多个dataSources,因此,如果您需要添加另一个dataSource,则只需更改application.yml,而无需更改代码。 但是,如果不使用,也可以删除也可以使用的liquibase!
在控制器的每次命中中,您需要获取X-TenantId标头,该标头将更改您的ThreadLocal,从而根据租户更改数据源
代码完整:https://github.com/dijalmasilva/spring-boot-multitenancy-datasource-liquibase
application.yml
spring:
dataSources:
- tenantId: db1
url: jdbc:postgresql://localhost:5432/db1
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
liquibase:
enabled: true
default-schema: public
change-log: classpath:db/master/changelog/db.changelog-master.yaml
- tenantId: db2
url: jdbc:postgresql://localhost:5432/db2
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
- tenantId: db3
url: jdbc:postgresql://localhost:5432/db3
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
TenantContext
public class TenantContext {
private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
static String getCurrentTenant() {
return currentTenant.get();
}
static void setCurrentTenant(String tenant) {
currentTenant.set(tenant);
}
static void clear() {
currentTenant.remove();
}
}
过滤到控制器
public class TenantFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final String X_TENANT_ID = "X-TenantID";
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
final String tenantId = httpServletRequest.getHeader(X_TENANT_ID);
if (tenantId == null) {
final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write("{\"error\": \"No tenant header supplied\"}");
response.getWriter().flush();
TenantContext.clear();
return;
}
TenantContext.setCurrentTenant(tenantId);
filterChain.doFilter(servletRequest, servletResponse);
}
}
配置类(如果使用liquibase)
@Configuration
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(LiquibaseProperties.class)
@AllArgsConstructor
public class LiquibaseConfiguration {
private LiquibaseProperties properties;
private DataSourceProperties dataSourceProperties;
@Bean
@DependsOn("tenantRoutingDataSource")
public MultiTenantDataSourceSpringLiquibase liquibaseMultiTenancy(Map<Object, Object> dataSources,
@Qualifier("taskExecutor") TaskExecutor taskExecutor) {
// to run changeSets of the liquibase asynchronous
MultiTenantDataSourceSpringLiquibase liquibase = new MultiTenantDataSourceSpringLiquibase(taskExecutor);
dataSources.forEach((tenant, dataSource) -> liquibase.addDataSource((String) tenant, (DataSource) dataSource));
dataSourceProperties.getDataSources().forEach(dbProperty -> {
if (dbProperty.getLiquibase() != null) {
liquibase.addLiquibaseProperties(dbProperty.getTenantId(), dbProperty.getLiquibase());
}
});
liquibase.setContexts(properties.getContexts());
liquibase.setChangeLog(properties.getChangeLog());
liquibase.setDefaultSchema(properties.getDefaultSchema());
liquibase.setDropFirst(properties.isDropFirst());
liquibase.setShouldRun(properties.isEnabled());
return liquibase;
}
}
代码完整:https://github.com/dijalmasilva/spring-boot-multitenancy-datasource-liquibase