如何使用 Hibernate 配置多个模式

How to configure multiple schemas with Hibernate

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

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

如果有办法请告诉我。

您可以在为您的实体定义 table 时通过 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 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 来隐藏 user/password 凭据。

与 Vlad Mihalcea 的回答相反,该回答解释了多个数据库租户的连接提供程序,模式的方法在 this url

中解释如下