Spring boot Spring Boot如何在运行时重用现有连接更改数据库?

Spring boot Spring Boot如何在运行时重用现有连接更改数据库?,spring-boot,hibernate,Spring Boot,Hibernate,我使用的是SpringBoot2.4,通过SpringBoot自动配置和Spring数据连接到MySQL 8.x 现在,我需要切换到多租户方法,在这种方法中,对于每个客户,我都有一个数据库。客户的数量不是固定的 根据所有教程,我发现问题在于每个数据库都会创建一个新的连接(池)。通过这种方式,我的应用程序创建了很多数据库连接 是否可以重用现有连接并为每个sql命令指定数据库 这里是我正在使用的配置 public class MultiTenantStorage { private stat

我使用的是SpringBoot2.4,通过SpringBoot自动配置和Spring数据连接到MySQL 8.x

现在,我需要切换到多租户方法,在这种方法中,对于每个客户,我都有一个数据库。客户的数量不是固定的

根据所有教程,我发现问题在于每个数据库都会创建一个新的连接(池)。通过这种方式,我的应用程序创建了很多数据库连接

是否可以重用现有连接并为每个sql命令指定数据库

这里是我正在使用的配置

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;
}
}
您试过了吗?