You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Schema的多租户实现问题:getConnection()未被调用

Hibernate基于Schema的多租户切换异常:getConnection方法未被调用

我正在实现基于Schema的多租户功能,但切换Schema时遇到问题,具体流程如下:

  1. 通过请求头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;
    }

}
  1. 实现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;
    }
}
  1. 问题核心:理论上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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 04:54:16