【问题标题】:How to configure multiple schemas with Hibernate如何使用 Hibernate 配置多个模式
【发布时间】:2017-01-16 13:17:30
【问题描述】:

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

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

如果有办法请告诉我。

【问题讨论】:

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


    【解决方案1】:

    您可以在为实体定义表时通过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 了解更多详细信息以映射多个架构,但它不是特定于休眠的。

    【讨论】:

      【解决方案2】:

      感谢Hibernate Multitenancy support,您可以轻松做到这一点:

      下面的例子可以在Hibernate ORM documentation folder找到。

      每个 schema 都可以是一个租户,所以你只需要给 Hibernate Session 提供一个租户标识符,Hibernate 就会知道要连接什么数据库 schema:

      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,该DataSource 隐藏用户/密码凭据。

      【讨论】:

      • 您好,谢谢,但我们使用了同义词。问题已解决。
      • 这个属性()方法。它在哪里定义?是不是对象初始化,所以应该是 .. = new Properties() ?
      • 查看我回答的第二段。
      • 我发现返回这个Properties对象的是org.Hibernate.Configuration.getProperties()。
      【解决方案3】:

      与 Vlad Mihalcea 的回答相反,它解释了几个数据库租户的连接提供程序,模式的方法在 this url 中解释如下:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-19
        • 2015-09-01
        • 2010-12-12
        • 1970-01-01
        • 2019-02-01
        • 2022-08-04
        • 1970-01-01
        • 2010-12-10
        相关资源
        最近更新 更多