启用多个数据源时,TenantConnectionProvider 找不到数据源

问题描述 投票:0回答:1

我正在创建一个使用多租户的 Spring Kotlin 应用程序。我想向我的应用程序添加第二个数据源。

使用 Spring Boot JPA 自动配置,多租户可以在单个数据源上正常工作。我不需要创建任何 DatasourceConfiguration 类。

由于我想添加第二个数据源,所以我不能再依赖自动配置,而是必须为每个数据源创建配置类,如下所示:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    transactionManagerRef = "transactionManagerA",
    entityManagerFactoryRef = "entityManagerFactoryA",
    basePackages = ["com.myapp.repository.a"]
)
class DataSourceConfigA {
}

多租户是通过

TenantConnectionProvider
类启用的,如下所示:

@Component
class TenantConnectionProvider :
    MultiTenantConnectionProvider,
    HibernatePropertiesCustomizer {

    @Autowired
    private lateinit var datasource: DataSource

    override fun getAnyConnection(): Connection = datasource.connection
   
    ...
}

由于我添加了

DataSourceConfig
类来配置多个数据源,
datasource
中的
TenantConnectionProvider
不再自动装配,并且使用多租户的数据库查询失败。

我收到以下错误:

lateinit property dataSource has not been initialized

为什么禁用 JPA 自动配置会破坏我的

TenantConfigProvider
中的数据源自动装配?

如何在 Spring Boot Kotlin 应用程序中结合多租户和多个数据源?

spring kotlin datasource multi-tenant boot
1个回答
0
投票

MultiTenantConnectionProviderInitializor 类上取得峰值,它为您的应用程序提供

TenantConnectionProvider

它从

hibernate.multi_tenant_connection_provider
中搜索
application.yml
配置值。如果它能找到它,它会检查该类是否是
MultiTenantConnectionProvider
的实例,然后返回该类。

在上面的代码中,配置是一个字符串(

com.myapp.config.TenantConnectionProvider
),发起者最终尝试使用
implClass.newInstance()
实例化该类,而不自动装配任何bean。
datasource
未初始化,以后的任何连接都将失败。

在数据源配置类中,您可以覆盖

hibernate.multi_tenant_connection_provider
属性以使用使用注入 bean 的
TenantConnectionProvider
实例,如下所示:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    transactionManagerRef = "transactionManagerA",
    entityManagerFactoryRef = "entityManagerFactoryA",
    basePackages = ["com.myapp.repository.a"]
)
class DataSourceConfigA {
    
    ...

    @Bean
    @Primary
    fun tenantConnectionProvider(): MultiTenantConnectionProvider = TenantConnectionProvider()
    
    @Bean(name = ["entityManagerFactoryA"])
    @Primary
    fun postgresEntityManagerFactory(
        dataSource: DataSource,
        builder: EntityManagerFactoryBuilder
    ): LocalContainerEntityManagerFactoryBean {
        return builder.dataSource(dataSource)
            .packages("com.myapp.domain.a")
            // Overwrite hibernate.multi_tenant_connection_provider to use a class instance
            .properties(mapOf(Pair("hibernate.multi_tenant_connection_provider", tenantConnectionProvider())))
            .build()
    }
    
    ...

}

这将导致发起者使用您自己的实例,而不是尝试实例化没有自动装配 bean 的类。

© www.soinside.com 2019 - 2024. All rights reserved.