基于Schema的多租户实现问题:getConnection()未被调用
Hibernate基于Schema的多租户切换异常:getConnection方法未被调用
我正在实现基于Schema的多租户功能,但切换Schema时遇到问题,具体流程如下:
- 通过请求头
X-TENANT-ID传递租户标识,用拦截器获取并设置到Tenant类中:
package br.com.braxxy.brxm.server.multtenant.hibernate; import java.util.Optional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import lombok.extern.slf4j.Slf4j; @Slf4j public class TenantInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("TENANT: " + request.getHeader("X-TENANT-ID")); Optional.ofNullable(request.getHeader("X-TENANT-ID")).map(String::toUpperCase) .ifPresent(Tenant::setIdentificador); return true; } }
- 实现
CurrentTenantIdentifierResolver接口,返回当前租户标识:
package br.com.braxxy.brxm.server.multtenant.hibernate; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; public class SchemaCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver { @Override public String resolveCurrentTenantIdentifier() { System.out.println("resolveCurrentTenantIdentifier : " + Tenant.getIdentificador()); return Tenant.getIdentificador(); } @Override public boolean validateExistingCurrentSessions() { System.out.println("validateExistingCurrentSessions : " + Tenant.getIdentificador()); return false; } }
- 问题核心:理论上Hibernate应该调用
MultiTenantConnectionProvider的getConnection(String tenantIdentifier)方法来切换Schema,但实际请求时该方法并未触发,导致Schema无法切换:
package br.com.braxxy.brxm.server.multtenant.hibernate; import org.hibernate.HibernateException; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; import java.sql.Connection; import java.sql.SQLException; import java.util.Map; public class SchemaMultiTenantConnectionProvider implements MultiTenantConnectionProvider, ServiceRegistryAwareService { /** * */ private static final long serialVersionUID = 1L; private ConnectionProvider connectionProvider = null; @Override public Connection getAnyConnection() throws SQLException { return connectionProvider.getConnection(); } @Override public void releaseAnyConnection(Connection connection) throws SQLException { connectionProvider.closeConnection(connection); } @Override public Connection getConnection(String tenantIdentifier) throws SQLException { Connection connection = getAnyConnection(); System.out.println("getConnection :" + tenantIdentifier); try { connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'"); } catch (SQLException e) { throw new HibernateException("Could not change to schema " + tenantIdentifier + ".", e); } return connection; } @Override public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException { releaseAnyConnection(connection); } @Override public boolean supportsAggressiveRelease() { return false; } @Override public boolean isUnwrappableAs(Class unwrapType) { return false; } @Override public <T> T unwrap(Class<T> unwrapType) { return null; } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { Map<String, String> settings = serviceRegistry .getService(ConfigurationService.class) .getSettings(); connectionProvider = new DriverManagerConnectionProviderImpl(); ((DriverManagerConnectionProviderImpl) connectionProvider) .injectServices(serviceRegistry); ((DriverManagerConnectionProviderImpl) connectionProvider) .configure(settings); } }
相关persistence配置文件:
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd" version="2.2"> <persistence-unit name="brxTenant"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <property name="javax.persistence.provider" value="org.hibernate.ejb.HibernatePersistence" /> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres" /> <property name="javax.persistence.jdbc.user" value="postgres" /> <property name="javax.persistence.jdbc.password" value="braxxy" /> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" /> <property name="hibernate.archive.autodetection" value="class, hbm" /> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.multiTenancy" value="SCHEMA" /> <property name="hibernate.multi_tenant_connection_provider" value="br.com.braxxy.brxm.server.multtenant.hibernate.SchemaMultiTenantConnectionProvider"/> <property name="hibernate.tenant_identifier_resolver" value="br.com.braxxy.brxm.server.multtenant.hibernate.SchemaCurrentTenantIdentifierResolver"/> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> </properties> </persistence-unit> </persistence>
我尝试了多种方法都无法解决,请问该如何处理?
内容的提问来源于stack exchange,提问作者Kelvyn Cavalcante
相关产品推荐
相关产品推荐

