Hibernate Multitenant problem with current tenancy ID

2

I'm using the hibernate multitenant for schemas, I use the Postgresql database.

My problem is the following I have a service where I do a select in a public schema table, then for each item returned I have to go to the client schema and make a select in another table and update some information, well then my problem is on how to identify the tenant exchange, see my persistence.xml

    <properties>
        <property name="hibernate.connection.datasource" value="jdbc/GestaoRural" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect" />
        <property name="hibernate.enable_lazy_load_no_trans" value="true" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.multiTenancy" value="SCHEMA" />
        <property name="hibernate.tenant_identifier_resolver" value="com.hermes.multitenant.MultiTenantSchemaResolver" />
        <property name="hibernate.multi_tenant_connection_provider" value="com.hermes.multitenant.MultiTenantProvider" />
    </properties>

Here I have the class responsible for identifying the tenant, current I get this information of what was set manually or the user logged in, if there is no return null and return the schema public.

public class MultiTenantSchemaResolver implements CurrentTenantIdentifierResolver {

/**
 * Schema padrão.
 */
private  static final String DEFAULT_SCHEMA = "public";

@Override
public String resolveCurrentTenantIdentifier() {

    String tenant = TenancyContext.getCurrentTenant();
    if (tenant != null) {
        return tenant;
    }

    return DEFAULT_SCHEMA;
}

@Override
public boolean validateExistingCurrentSessions() {
    return true;
}

What happens is that when I do the select in the public schema table it calls the method and returns the schema public correction, the problem is that when it will execute the second query the method responsible for the schema ID is no longer called , I think I'm forgetting something but I do not know what it can be, does anyone have any tips to give me?

MultiTenantProvider

public class MultiTenantProvider extends DataSourceBasedMultiTenantConnectionProviderImpl {

    private static final Logger LOGGER = Logger.getLogger(MultiTenantProvider.class.getName());

    @Override
    public Connection getAnyConnection() throws SQLException {
        return selectAnyDataSource().getConnection();
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException {
        connection.close();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {

        final Connection connection = selectAnyDataSource().getConnection();
        try {
            connection.createStatement().execute("SET SCHEMA " + toSchema(tenantIdentifier));
        } catch (SQLException e) {
            LOGGER.log(Level.SEVERE, "Não foi possível alterar a conexão JDBC para esquema especificado ["
                + tenantIdentifier + "]");
            throw new HibernateException(e);
        }

        return connection;
    }

    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {

        try {
            connection.createStatement().execute("SET SCHEMA 'public'");
        } catch (SQLException e) {
            LOGGER.log(Level.SEVERE, "Não foi possível alterar a conexão JDBC para esquema especificado [public]");
        }
        connection.close();
    }

    /**
     * Converter um domínio para uma expressão de um schema do banco de dados.
     * 
     * @param domain tenant domain
     * @return dominio formatado
     */
    private String toSchema(String domain) {

        final int bufferSize = 4;

        int size = domain.length() + bufferSize;

        StringBuffer buffer = new StringBuffer(size);
        buffer.append("'");
        buffer.append(domain);
        buffer.append("'");
        return buffer.toString();
    }

}
    
asked by anonymous 17.11.2015 / 23:51

1 answer

2

The MultiTenantSchemaResolver is only responsible for defining which schema will be used, the "magic" of the schema exchange is MultiTenantProvider . See these overloads for methods getAnyConnection() and getConnection(String tenantIdentifier) :

    private ComboPooledDataSource cpds;

    @Override
    public Connection getAnyConnection() throws SQLException {
        return cpds.getConnection();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        Connection connection = cpds.getConnection();
        connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
        return connection;
    }

This is a simplified version of the implementation, but realize that when requesting a connection, the method requests the pool, which in turn will do the job of requesting hibernate to resolve the tenant and later call getConnection(String tenant) , this will do the schema change in practice.

If everything at this point is ok, it may be that you are doing everything with the same connection, without requiring another one to hibernate, so everything would still be executed in the same schema.

    
18.11.2015 / 12:04