问题
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