How to configure multiple schemas with Hibernate

早过忘川 提交于 2021-02-19 06:43:46

问题


We have got a requirement for multiple schemas in Hibernate.

In our project, we need to connect to multiple schemas based on the username and password. But how to configure multiple schemas in Hibernate?

Please let me know if there's a way.


回答1:


Thanks to Hibernate Multitenancy support, you can easily do that as follows:

The following examples can be found in the Hibernate ORM documentation folder.

Each schema can be a tenant, so you only need to provide a tenant identifier to the Hibernate Session, and Hibernate will know what database schema to connect to:

private void doInSession(String tenant, Consumer<Session> function) {
    Session session = null;
    Transaction txn = null;
    try {
        session = sessionFactory
            .withOptions()
            .tenantIdentifier( tenant )
            .openSession();
        txn = session.getTransaction();
        txn.begin();
        function.accept(session);
        txn.commit();
    } catch (Throwable e) {
        if ( txn != null ) txn.rollback();
        throw e;
    } finally {
        if (session != null) {
            session.close();
        }
    }
}

You need to provide a MultiTenantConnectionProvider implementation as well:

public class ConfigurableMultiTenantConnectionProvider
        extends AbstractMultiTenantConnectionProvider {

    private final Map<String, ConnectionProvider> connectionProviderMap =
        new HashMap<>(  );

    public ConfigurableMultiTenantConnectionProvider(
            Map<String, ConnectionProvider> connectionProviderMap) {
        this.connectionProviderMap.putAll( connectionProviderMap );
    }

    @Override
    protected ConnectionProvider getAnyConnectionProvider() {
        return connectionProviderMap.values().iterator().next();
    }

    @Override
    protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
        return connectionProviderMap.get( tenantIdentifier );
    }
}

And you can initialize it as follows:

private void init() {
    registerConnectionProvider( FRONT_END_TENANT );
    registerConnectionProvider( BACK_END_TENANT );

    Map<String, Object> settings = new HashMap<>(  );

    settings.put( AvailableSettings.MULTI_TENANT, multiTenancyStrategy() );
    settings.put( AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER,
        new ConfigurableMultiTenantConnectionProvider( connectionProviderMap ) );

    sessionFactory = sessionFactory(settings);
}

protected void registerConnectionProvider(String tenantIdentifier) {
    Properties properties = properties();
    properties.put( Environment.URL,
        tenantUrl(properties.getProperty( Environment.URL ), tenantIdentifier) );

    DriverManagerConnectionProviderImpl connectionProvider =
        new DriverManagerConnectionProviderImpl();
    connectionProvider.configure( properties );
    connectionProviderMap.put( tenantIdentifier, connectionProvider );
}

Since this example uses H2, the tenantUrl is defined like this:

public static final String SCHEMA_TOKEN = ";INIT=CREATE SCHEMA IF NOT EXISTS %1$s\\;SET SCHEMA %1$s";

@Override
protected String tenantUrl(String originalUrl, String tenantIdentifier) {
    return originalUrl + String.format( SCHEMA_TOKEN, tenantIdentifier );
}

Now you can just use separate tenants and schemas from the same SessionFactory:

doInSession( FRONT_END_TENANT, session -> {
    Person person = new Person(  );
    person.setId( 1L );
    person.setName( "John Doe" );
    session.persist( person );
} );

doInSession( BACK_END_TENANT, session -> {
    Person person = new Person(  );
    person.setId( 1L );
    person.setName( "John Doe" );
    session.persist( person );
} );

Since the MultiTenantConnectionProvider acts like any other ConnectionProvider, you can configure each tenant to use a separate DataSource which hides the user/password credentials.




回答2:


You can specify it by schema element while defining table for your entity.

@Table(name="TABLE_NAME", schema="SCHEMA_NAME")

Else, you can use separate EntityManager pointing to respective schema & then use the same entity, as their structure is similar.


Edit : You can have separate configuration files for each schema & then build SessionFactory from it, below is some pseudo-code for it.

SessionFactory sf_1 = new  Configuration().configure("schema1config.cfg.xml").buildSessionFactory();
SessionFactory sf_2 = new Configuration().configure("schema2config.cfg.xml").buildSessionFactory();

session_1 = sf_1.openSession();  //-- Similarly for other

You can refer this link for further details to map multiple schema, but it isn't hibernate specific.




回答3:


As Opposed to Vlad Mihalcea's answer, which is explaining the connection providers for several database tenants, the approach for schemas are explained as follows in this url



来源:https://stackoverflow.com/questions/39393773/how-to-configure-multiple-schemas-with-hibernate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!