我正在创建一个多租户Spring Boot-JPA应用程序。
在此应用程序中,我想使用通过API请求作为标头发送的数据库名称连接到MySQL数据库。
我在线检查了许多多租户项目示例,但仍然找不到解决方案。
有人可以建议我这样做吗?
答案 0 :(得分:1)
您可以使用AbstractRoutingDataSource
来实现。 AbstractRoutingDataSource
需要信息来知道要路由到哪个实际DataSource
(称为 Context ),这是由determineCurrentLookupKey()
方法提供的。使用here中的示例。
定义上下文,例如:
public enum ClientDatabase {
CLIENT_A, CLIENT_B
}
然后,您需要定义将在determineCurrentLookupKey()
public class ClientDatabaseContextHolder {
private static ThreadLocal<ClientDatabase> CONTEXT = new ThreadLocal<>();
public static void set(ClientDatabase clientDatabase) {
Assert.notNull(clientDatabase, "clientDatabase cannot be null");
CONTEXT.set(clientDatabase);
}
public static ClientDatabase getClientDatabase() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
然后您可以像下面这样扩展AbstractRoutingDataSource
:
public class ClientDataSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return ClientDatabaseContextHolder.getClientDatabase();
}
}
最后,DataSource
bean配置:
@Bean
public DataSource clientDatasource() {
Map<Object, Object> targetDataSources = new HashMap<>();
DataSource clientADatasource = clientADatasource();
DataSource clientBDatasource = clientBDatasource();
targetDataSources.put(ClientDatabase.CLIENT_A,
clientADatasource);
targetDataSources.put(ClientDatabase.CLIENT_B,
clientBDatasource);
ClientDataSourceRouter clientRoutingDatasource
= new ClientDataSourceRouter();
clientRoutingDatasource.setTargetDataSources(targetDataSources);
clientRoutingDatasource.setDefaultTargetDataSource(clientADatasource);
return clientRoutingDatasource;
}
答案 1 :(得分:0)
https://github.com/wmeints/spring-multi-tenant-demo
按照这个逻辑,我现在可以解决它。一些版本需要升级,代码也需要升级。
Spring Boot版本已更改。
org.springframework.boot 弹簧启动启动器父母 2.1.0。发布
MySQL版本已被删除。
MultitenantConfiguration.java
中的一些小变化
@Configuration
public class MultitenantConfiguration {
@Autowired
private DataSourceProperties properties;
/**
* Defines the data source for the application
* @return
*/
@Bean
@ConfigurationProperties(
prefix = "spring.datasource"
)
public DataSource dataSource() {
File[] files = Paths.get("tenants").toFile().listFiles();
Map<Object,Object> resolvedDataSources = new HashMap<>();
if(files != null) {
for (File propertyFile : files) {
Properties tenantProperties = new Properties();
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader());
try {
tenantProperties.load(new FileInputStream(propertyFile));
String tenantId = tenantProperties.getProperty("name");
dataSourceBuilder.driverClassName(properties.getDriverClassName())
.url(tenantProperties.getProperty("datasource.url"))
.username(tenantProperties.getProperty("datasource.username"))
.password(tenantProperties.getProperty("datasource.password"));
if (properties.getType() != null) {
dataSourceBuilder.type(properties.getType());
}
resolvedDataSources.put(tenantId, dataSourceBuilder.build());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
// Create the final multi-tenant source.
// It needs a default database to connect to.
// Make sure that the default database is actually an empty tenant database.
// Don't use that for a regular tenant if you want things to be safe!
MultitenantDataSource dataSource = new MultitenantDataSource();
dataSource.setDefaultTargetDataSource(defaultDataSource());
dataSource.setTargetDataSources(resolvedDataSources);
// Call this to finalize the initialization of the data source.
dataSource.afterPropertiesSet();
return dataSource;
}
/**
* Creates the default data source for the application
* @return
*/
private DataSource defaultDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader())
.driverClassName(properties.getDriverClassName())
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword());
if(properties.getType() != null) {
dataSourceBuilder.type(properties.getType());
}
return dataSourceBuilder.build();
}
}
此更改是由于DataSourceBuilder
已移至另一路径并且其构造函数已更改。
还像这样在application.properties
中更改了MySQL驱动程序类名称
spring.datasource.driver-class-name = com.mysql.jdbc.Driver