如何使用Hibernate配置多个模式

时间:2016-09-08 14:36:07

标签: spring hibernate orm hibernate-mapping hibernate-criteria

我们在Hibernate中需要多个模式。

在我们的项目中,我们需要根据用户名和密码连接到多个模式。但是如何在Hibernate中配置多个模式?

如果有办法,请告诉我。

3 个答案:

答案 0 :(得分:3)

您可以在为实体定义表时按schema元素指定。

  

@Table(name =“TABLE_NAME”,schema =“SCHEMA_NAME”)

否则,您可以使用单独的EntityManager指向相应的架构&然后使用相同的实体,因为它们的结构相似。

编辑:您可以为每个架构设置单独的配置文件。然后从中构建SessionFactory,下面是一些伪代码。

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

您可以参考this link以获取有关映射多个架构的更多详细信息,但它不是特定于hibernate的。

答案 1 :(得分:2)

感谢Hibernate Multitenancy support,您可以轻松完成以下操作:

以下示例可在Hibernate ORM documentation folder

中找到

每个模式都可以是租户,因此您只需要为Hibernate Session提供租户标识符,Hibernate将知道要连接到哪个数据库模式:

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();
        }
    }
}

您还需要提供MultiTenantConnectionProvider实施:

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 );
    }
}

您可以按如下方式初始化它:

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 );
}

由于此示例使用H2,tenantUrl的定义如下:

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 );
}

现在,您可以使用来自同一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 );
} );

由于MultiTenantConnectionProvider的行为与任何其他ConnectionProvider相同,因此您可以将每个租户配置为使用单独的DataSource来隐藏用户/密码凭据。

答案 2 :(得分:0)

与弗拉德·米哈尔恰(Vlad Mihalcea)的答案相反,该答案解释了多个数据库租户的连接提供者,模式的方法在this url

中进行了解释。