Spring boot Spring Boot如何在运行时重用现有连接更改数据库?
我使用的是SpringBoot2.4,通过SpringBoot自动配置和Spring数据连接到MySQL 8.x 现在,我需要切换到多租户方法,在这种方法中,对于每个客户,我都有一个数据库。客户的数量不是固定的 根据所有教程,我发现问题在于每个数据库都会创建一个新的连接(池)。通过这种方式,我的应用程序创建了很多数据库连接 是否可以重用现有连接并为每个sql命令指定数据库 这里是我正在使用的配置Spring boot Spring Boot如何在运行时重用现有连接更改数据库?,spring-boot,hibernate,Spring Boot,Hibernate,我使用的是SpringBoot2.4,通过SpringBoot自动配置和Spring数据连接到MySQL 8.x 现在,我需要切换到多租户方法,在这种方法中,对于每个客户,我都有一个数据库。客户的数量不是固定的 根据所有教程,我发现问题在于每个数据库都会创建一个新的连接(池)。通过这种方式,我的应用程序创建了很多数据库连接 是否可以重用现有连接并为每个sql命令指定数据库 这里是我正在使用的配置 public class MultiTenantStorage { private stat
public class MultiTenantStorage {
private static final ThreadLocal<String> currentTenant = new InheritableThreadLocal<>();
public static void setCurrentTenant(String tenantId) {
currentTenant.set(tenantId);
}
public static String getCurrentTenant() {
return currentTenant.get();
}
}
public class MultiTenantSchemaResolver implements CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
return MultiTenantStorage.getCurrentTenant();
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
public class MultiTenantDataSource {
private final Map<String, DataSource> dataSources;
private final String dbUrlReusablePart;
private final String dbUser;
private final String dbPassword;
public MultiTenantDataSource(@Value("${spring.datasource.url}") String dbUrl,
@Value("${spring.datasource.username}") String dbUser,
@Value("${spring.datasource.password}") String dbPassword
) {
this.dbUser = dbUser;
this.dbPassword = dbPassword;
dataSources = new HashMap<>();
dbUrlReusablePart = dbUrl.substring(0, dbUrl.lastIndexOf('/'));
}
public DataSource getDataSource(String name) {
return dataSources.computeIfAbsent(name, this::createDataSource);
}
private DataSource createDataSource(String name) {
return DataSourceBuilder
.create().driverClassName("com.mysql.cj.jdbc.Driver")
.username(dbUser)
.password(dbPassword)
.url(dbUrlReusablePart + "/" + name)
.build();
}
}
public class DataSourceBasedMultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private final DataSource defaultDataSource;
private final ApplicationContext context;
public DataSourceBasedMultiTenantConnectionProviderImpl(DataSource defaultDataSource, ApplicationContext context) {
this.defaultDataSource = defaultDataSource;
this.context = context;
}
@Override
protected DataSource selectAnyDataSource() {
return defaultDataSource;
}
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
return context.getBean(MultiTenantDataSource.class).getDataSource(tenantIdentifier);
}
}
@Configuration
public class HibernateConfig {
private final JpaProperties jpaProperties;
public HibernateConfig(JpaProperties jpaProperties) {
this.jpaProperties = jpaProperties;
}
@Bean
JpaVendorAdapter jpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource,
MultiTenantConnectionProvider multiTenantConnectionProviderImpl,
CurrentTenantIdentifierResolver currentTenantIdentifierResolverImpl
) {
Map<String, Object> jpaPropertiesMap = new HashMap<>(jpaProperties.getProperties());
jpaPropertiesMap.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
jpaPropertiesMap.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProviderImpl);
jpaPropertiesMap.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolverImpl);
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.mycompany.persistence*");
em.setJpaVendorAdapter(this.jpaVendorAdapter());
em.setJpaPropertyMap(jpaPropertiesMap);
return em;
}
}
公共类多租户存储{
private static final ThreadLocal currentTenant=new InheritableThreadLocal();
公共静态无效setCurrentTenant(字符串tenantId){
currentTenant.set(tenantId);
}
公共静态字符串getCurrentTenant(){
返回currentTenant.get();
}
}
公共类MultiTenantSchemaResolver实现CurrentTenantIdentifierResolver{
@凌驾
公共字符串resolveCurrentTenantIdentifier(){
返回MultiTenantStorage.getCurrentTenant();
}
@凌驾
公共布尔值validateExistingCurrentSessions(){
返回true;
}
}
公共类多租户数据源{
私有最终地图数据源;
私有最终字符串dbUrlReusablePart;
私有最终字符串dbUser;
私有最终字符串dbPassword;
公共MultiTenantDataSource(@Value(${spring.datasource.url}”)字符串dbUrl,
@值(${spring.datasource.username}”)字符串dbUser,
@值(“${spring.datasource.password}”)字符串dbPassword
) {
this.dbUser=dbUser;
this.dbPassword=dbPassword;
dataSources=newhashmap();
dbUrlReusablePart=dbUrl.substring(0,dbUrl.lastIndexOf('/');
}
公共数据源getDataSource(字符串名称){
return dataSources.computeIfAbsent(名称,this::createDataSource);
}
专用数据源createDataSource(字符串名称){
返回数据源生成器
.create().driverClassName(“com.mysql.cj.jdbc.Driver”)
.username(dbUser)
.password(dbPassword)
.url(dbUrlReusablePart+“/”+名称)
.build();
}
}
公共类DataSourceBasedMultiTenantConnectionProviderImpl扩展了AbstractDataSourceBasedMultiTenantConnectionProviderImpl{
私有最终数据源defaultDataSource;
私有最终应用程序上下文上下文;
基于公共数据源的多租户连接ProviderImpl(数据源默认数据源,应用程序上下文){
this.defaultDataSource=defaultDataSource;
this.context=上下文;
}
@凌驾
受保护的数据源selectAnyDataSource(){
返回默认数据源;
}
@凌驾
受保护的数据源selectDataSource(字符串租户标识符){
返回context.getBean(MultiTenantDataSource.class).getDataSource(tenantIdentifier);
}
}
@配置
公共类HibernateConfig{
私人最终JPA财产JPA财产;
公共HibernateConfig(JPA属性JPA属性){
this.jpaProperties=jpaProperties;
}
@豆子
JpaVendorAdapter JpaVendorAdapter(){
返回新的HibernateJavaEndorapter();
}
@豆子
LocalContainerEntityManagerFactoryBean entityManagerFactory(
数据源数据源,
MultiTenantConnectionProvider multiTenantConnectionProviderImpl,
CurrentTenantIdentifierResolver currentTenantIdentifierResolverImpl
) {
Map jpaPropertiesMap=newhashmap(jpaProperties.getProperties());
jpaPropertiesMap.put(Environment.MULTI_-TENANT,MULTI-tenancystategy.DATABASE);
jpaPropertiesMap.put(Environment.MULTI_-TENANT_-CONNECTION_-PROVIDER,MULTI-tenantconnectionproviderImpl);
jpaPropertiesMap.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER,currentTenantIdentifierResolverImpl);
LocalContainerEntityManagerFactoryBean em=新的LocalContainerEntityManagerFactoryBean();
em.setDataSource(数据源);
em.setPackagesToScan(“com.mycompany.persistence*”;
em.setJpaVendorAdapter(this.jpaVendorAdapter());
em.setJpaPropertyMap(jpaPropertiesMap);
返回em;
}
}
您试过了吗?