[英]Using multiple Spring Boot and JDBC dataSources
I have the following issue that I have to solve in my business.我有以下问题需要在我的业务中解决。 I am using
Spring
for project development I have 8 dataSource to connect.我正在使用
Spring
进行项目开发,我有 8 个数据源要连接。
A request will be made informing the contract number, through this contact number I will have to select one of the 8 dataSource and make the client consultation.将请求告知合同编号,通过此联系电话,我必须选择 8 个数据源之一并进行客户咨询。
Example: I have the base Brazil = 1
, Spain = 2
and Germany = 3
示例:我有基础
Brazil = 1
, Spain = 2
和Germany = 3
id = 1
, then you should get the customer data from Brazil base
.id = 1
,那么您应该从Brazil base
获取客户数据。id = 2
, then you should get the customer data from Spain base
.id = 2
,那么您应该从Spain base
获取客户数据。id = 3
, then you should fetch customer data from the Germany base
.id = 3
,那么您应该从Germany base
获取客户数据。 I don't know how to solve this problem if I use multitenancy
or AbstractRouting
.如果我使用
multitenancy
或AbstractRouting
我不知道如何解决这个问题。 And I don't know how to start the code for this.我不知道如何为此启动代码。
Would anyone have any solution and an example?有没有人有任何解决方案和例子?
Spring has way to determine datasource dynamically using AbstractRoutingDataSource
. Spring 可以使用
AbstractRoutingDataSource
动态确定数据源。 But need to use ThreadLocal
to bind context to current thread.但需要使用
ThreadLocal
将上下文绑定到当前线程。
This may complicate things if you are spawning multiple threads or using async in your app.如果您在应用程序中生成多个线程或使用异步,这可能会使事情复杂化。
You can refer simple exmaple here你可以在这里参考简单的例子
If you really need to create database connection as per different clients then hibernate provides a way to manage Multi-tenancy
, Hibernate Guide .如果您确实需要根据不同的客户端创建数据库连接,那么 hibernate 提供了一种管理
Multi-tenancy
, Hibernate Guide 。 As explained general approach would be to use connection pool per-tenant or single connection pool per all tenants sharing same database but different schema.正如所解释的,一般方法是使用每个租户的连接池或每个共享相同数据库但不同架构的租户的单个连接池。
Below are the two implementation used to switch to multiple tenants -以下是用于切换到多个租户的两个实现 -
public class TestDataSourceBasedMultiTenantConnectionProviderImpl
extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 14535345L;
@Autowired
private DataSource defaultDataSource;
@Autowired
private TestDataSourceLookup dataSourceLookup;
/**
*
* Select datasources in situations where not tenantId is used (e.g. startup
* processing).
*
*/
@Override
protected DataSource selectAnyDataSource() {
//logger.trace("Select any dataSource: " + defaultDataSource);
return defaultDataSource;
}
/**
*
* Obtains a DataSource based on tenantId
*
*/
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
DataSource ds = dataSourceLookup.getDataSource(tenantIdentifier);
// logger.trace("Select dataSource from " + tenantIdentifier + ": " + ds);
return ds;
}
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.springframework.beans.factory.annotation.Autowired;
public class TestCurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
@Autowired
private RequestContext context;
@Override
public String resolveCurrentTenantIdentifier() {
// TODO Auto-generated method stub
return context.getTenantID();
}
@Override
public boolean validateExistingCurrentSessions() {
// TODO Auto-generated method stub
return true;
}
}
AbstractRouting would be a way to do it, indeed. AbstractRouting 确实是一种方法。 You can mix that approach with headers on the request to easily implement multi-tenancy.
您可以将该方法与请求的标头混合使用,以轻松实现多租户。 The link provided in another post on Baeldung does indeed provide a solution using such construct.
Baeldung上的另一篇文章中提供的链接确实提供了使用这种构造的解决方案。
Sharding and deploying a separate micro-service for each tenant, with a routing service in front, would be another one and I think it offers several benefits both from coding (no need for thread-locals or other similarly difficult construct) and maintenance perspective (you can take down your service for maintenance/customisation at tenant level), so it would be my solution of choice in your specific case, assuming that business requirements allow for it.为每个租户分片和部署一个单独的微服务,在前面有一个路由服务,这将是另一个,我认为它从编码(不需要线程局部或其他类似困难的构造)和维护角度提供了几个好处(您可以在租户级别取消您的服务以进行维护/定制),因此在您的特定情况下,这将是我选择的解决方案,假设业务需求允许。
Still, again, the best solution depends on your specific case.不过,最好的解决方案仍然取决于您的具体情况。
The easiest solution matching the title of the question - for readers that are not necessarily concerned with multi-tenancy - would be to create several dataSource instances in your Spring's @Configuration
beans, put them in a Map<Integer, DataSource>
and then return that Map<Integer, DataSource>
object as a Bean.与问题标题相匹配的最简单的解决方案 - 对于不一定关心多租户的读者 - 是在 Spring 的
@Configuration
bean 中创建多个 dataSource 实例,将它们放入Map<Integer, DataSource>
然后返回Map<Integer, DataSource>
对象作为 Bean。 When you have to access them, you access the Map
bean you created and then create your NamedParameterJdbcTemplate
or similar resource passing the specific DataSource
in the constructor.当您必须访问它们时,您可以访问您创建的
Map
bean,然后创建您的NamedParameterJdbcTemplate
或类似资源,并在构造函数中传递特定的DataSource
。
Pseudo-code example:伪代码示例:
@Configuration
class DataSourceConfig {
public final static int SPAIN = 2;
public final static int BRAZIL = 1;
@Bean
@Qualifier("dataSources")
public Map<Integer, DataSource> dataSources() {
Map<Integer, DataSource> ds = new HashMap<>();
ds.put(SPAIN, buildSpainDataSource());
ds.put(BRAZIL, buildBrazilDataSource());
return ds;
}
private DataSource buildSpainDataSource() {
...
}
private DataSource buildBrazilDataSource() {
...
}
}
@Service
class MyService {
@Autowired
@Qualifier("dataSources")
Map<Integer, DataSource> dataSources;
Map<String, Object> getObjectForCountry(int country) {
NamedParameterJdbcTemplate t = new NamedParameterJdbcTemplate(dataSources.get(country));
return t.queryForMap("select value from mytable", new HashMap<>());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.