为了使用Spring
Boot实现多租户,我们可以将AbstractRoutingDataSource用作所有“
租户数据库 ”的基础 DataSource 类。 __
它有一个抽象方法determineCurrentLookupKey我们必须重写。它告诉您当前必须使用
AbstractRoutingDataSource哪个租户数据源。因为它在多线程环境中工作,所以所选租户的信息应存储在
ThreadLocal变量中。
将
AbstractRoutingDataSource租户数据源的信息存储在其private中
Map<Object, Object>targetDataSources。该映射的键是 租户标识符 (例如String类型)和值- 租户数据源
。要将租户数据源放入此地图,我们必须使用其setter
setTargetDataSources。
如果
AbstractRoutingDataSource没有必须使用method设置的“默认”数据源,则无法使用
setDefaultTargetDataSource(ObjectdefaultTargetDataSource)。
设置租户数据源和默认数据源后,我们必须调用方法
afterPropertiesSet()来告知
AbstractRoutingDataSource来更新其状态。
所以我们的“ MultiTenantManager”类可以像这样:
@Configurationpublic class MultiTenantManager { private final ThreadLocal<String> currentTenant = new ThreadLocal<>(); private final Map<Object, Object> tenantDataSources = new ConcurrentHashMap<>(); private final DataSourceProperties properties; private AbstractRoutingDataSource multiTenantDataSource; public MultiTenantManager(DataSourceProperties properties) { this.properties = properties; } @Bean public DataSource dataSource() { multiTenantDataSource = new AbstractRoutingDataSource() { @Override protected Object determineCurrentLookupKey() { return currentTenant.get(); } }; multiTenantDataSource.setTargetDataSources(tenantDataSources); multiTenantDataSource.setDefaultTargetDataSource(defaultDataSource()); multiTenantDataSource.afterPropertiesSet(); return multiTenantDataSource; } public void addTenant(String tenantId, String url, String username, String password) throws SQLException { DataSource dataSource = DataSourceBuilder.create() .driverClassName(properties.getDriverClassName()) .url(url) .username(username) .password(password) .build(); // Check that new connection is 'live'. If not - throw exception try(Connection c = dataSource.getConnection()) { tenantDataSources.put(tenantId, dataSource); multiTenantDataSource.afterPropertiesSet(); } } public void setCurrentTenant(String tenantId) { currentTenant.set(tenantId); } private DriverManagerDataSource defaultDataSource() { DriverManagerDataSource defaultDataSource = new DriverManagerDataSource(); defaultDataSource.setDriverClassName("org.h2.Driver"); defaultDataSource.setUrl("jdbc:h2:mem:default"); defaultDataSource.setUsername("default"); defaultDataSource.setPassword("default"); return defaultDataSource; }}简要说明:
映射
tenantDataSources
它是我们放置到setTargetDataSources
设置程序中的本地租户数据源存储;DataSourceProperties properties
用于从spring.datasource.driverClassName
‘application.properties’ 的租户数据库获取数据库驱动程序类名称(例如org.postgresql.Driver
);方法
addTenant
用于将新的租户及其数据源添加到我们的本地租户数据源存储中。有了这种方法, 我们可以快速做到afterPropertiesSet()
;方法
setCurrentTenant(String tenantId)
用于“切换”到给定租户的数据源。例如,在处理使用数据库的请求时,我们可以在REST控制器中使用此方法。该请求应包含“ tenantId”,例如在X-TenantId
标头中,我们可以检索并放入此方法;defaultDataSource()
是使用内存中的H2数据库构建的,以避免在运行的SQL Server上使用默认数据库。
注意: 必须 将
spring.jpa.hibernate.ddl-auto参数设置为,
none以禁用Hibernate在数据库模式中进行更改。您必须事先创建租户数据库的架构。
此类的完整示例,您可以在我的 仓库中
找到更多示例。
更新
该分支演示了一个使用专用数据库存储租户数据库属性而不是属性文件的示例(请参见下面的@MarcoGustavo问题)。



