Spring Boot + Spring Data 多租户实现

15

是否可以配置Spring Boot使用MultiTenantConnectionProvider,以便系统的每个客户端连接到自己的私有数据库?

具体而言,我希望使用内置的Hibernate多租户支持:

这是我想要的配置示例,但我无法弄清如何在Spring Boot设置中使用它:

我尝试将这些属性添加到application.properties中:

spring.jpa.hibernate.multiTenancy=DATABASE
spring.jpa.hibernate.tenant_identifier_resolver=com.mystuff.MyCurrentTenantIdentifierResolver
spring.jpa.hibernate.multi_tenant_connection_provider=com.mystuff.MyMultiTenantConnectionProviderImplX

我也尝试编写自己的CurrentTenantIdentifierResolverMultiTenantConnectionProvider代码,并尝试从我的主要@Configuration bean中提供这些服务:

@Bean
public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() {
    return new CurrentTenantIdentifierResolver() {
        public String resolveCurrentTenantIdentifier() {
            // this is never called ...
        }
        public boolean validateExistingCurrentSessions() {
            // this is never called ...
        }
    };
}

@Bean
public MultiTenantConnectionProvider multiTenantConnectionProvider() {
    return new AbstractMultiTenantConnectionProvider() {
        protected ConnectionProvider getAnyConnectionProvider() {
            // this is never called ...
        }
        protected ConnectionProvider selectConnectionProvider(String s) {
            // this is never called ...
        }
    };
}

目前所有尝试都没有任何作用,因此我的问题是如何让spring-boot / spring-data使用这些多租户类?

谢谢你的帮助!


在这里看我的问题链接。<br/> 我使用LocalContainerEntityManagerFactoryBean,它有效。<br/> 但我并不完全理解这个和.yml.properties之间的区别。<br/>我同意@M.Deinum的观点,在yml中,Hibernate控制mulitTenantConnectionProviderCurrentTenantIdentifierResolver的生命周期。但我不知道为什么。 - linghu
1个回答

10

JPA/Hibernate中未定义的任何属性可以使用spring.jpa.properties属性在application.properties中设置。

您提供的示例有3个用于多租户的属性:

<prop key="hibernate.multiTenancy">SCHEMA</prop>
<prop key="hibernate.tenant_identifier_resolver">com.webapp.persistence.utility.CurrentTenantContextIdentifierResolver</prop>
<prop key="hibernate.multi_tenant_connection_provider">com.webapp.persistence.utility.MultiTenantContextConnectionProvider</prop>

转换为Spring Boot后,以下是在application.properties文件中的属性。

spring.jpa.properties.hibernate.multiTenancy=SCHEMA
spring.jpa.properties.hibernate.tenant_identifier_resolver=com.mystuff.MyCurrentTenantIdentifierResolver
spring.jpa.properties.hibernate.multi_tenant_connection_provider=com.webapp.persistence.utility.MultiTenantContextConnectionProvider

根据您的情况(如您在问题中所述)。
spring.jpa.properties.hibernate.multiTenancy=DATABASE
spring.jpa.properties.hibernate.tenant_identifier_resolver=com.webapp.persistence.utility.CurrentTenantContextIdentifierResolver 
spring.jpa.properties.hibernate.multi_tenant_connection_provider=com.mystuff.MyMultiTenantConnectionProviderImplX

无法与Spring管理的bean一起使用,因为Hibernate控制这些实例的生命周期。
有关更多属性,请参阅Spring Boot 参考指南

1
谢谢,我错过了“。properties。”这一点(回顾文档后很清楚,但我第一次读时错过了几次)。现在的挑战是生命周期方面,正如你所强调的那样。具体来说,是从ConnectionProvider内部获取其他Spring服务的访问权限。我尝试了保持对所需服务的静态引用的方法,但是Hibernate的东西会首先被创建,因此当我需要它时,它为空。备选方案是在这些类中不使用Spring服务,但这会使代码变得混乱。如果您对此有任何想法,我很乐意听取。 - zonski
1
虽然有点hacky,但你可以使用ContextLoader.getCurrentWebApplicationContext来访问上下文并进行查找。或者创建一个帮助类,用于检索服务。 - M. Deinum
1
是的,谢谢 - 我尝试了这两个方法,但无论Spring Boot在做什么,都会导致MultiTenantConnectionProvider在上下文存在之前被实例化,因此当首次调用getAnyConnectionProvider()时,ContextLoader.getCurrentWebApplicationContext()为空,并且此时辅助类也无法找到服务。我想我只能放弃在MultiTenantConnectionProvider内部使用Spring服务。很遗憾,但并非世界末日。非常感谢您的帮助! - zonski
同时,我们尝试使用Spring Data JPA从单租户转移到多租户,并采用每个租户一个数据库的策略,但是在使用@Service实例和@Transactional方法时,它看起来并不受支持... - Yuriy Nakonechnyy
不,它与那个没有任何关系。 - M. Deinum
实际上,使用Spring可以管理这两个Hibernate类的实例生命周期,并将它们注入到EntityManager中。请查看我的回答:https://dev59.com/Teo6XIcBkEYKwwoYNBln#31825971 - mhnagaoka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接