【问题标题】:Spring Data JPA, Hibernate Vendor, Multi-Tenancy and Postgres SQLSpring Data JPA、Hibernate 供应商、多租户和 Postgresql
【发布时间】:2014-02-12 10:15:50
【问题描述】:
package com.sd.multitenncy;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.service.ServiceRegistryBuilder;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.junit.Before;
import org.junit.Test;

import com.sd.config.MultiTenantConnectionProviderImpl;
import com.sd.config.MultiTenantIdentifierResolver;
import com.sd.entity.User;

public class DatabaseBasedMultiTenancyTest
{

  private ServiceRegistryImplementor serviceRegistry;
  private SessionFactoryImplementor sessionFactory;
  private MultiTenantIdentifierResolver currentTenantIdentifierResolver;

  @Before
  public void setUp()
  {
    Configuration config = new Configuration();
    config.getProperties().put(AvailableSettings.DIALECT,"org.hibernate.dialect.PostgreSQLDialect");
    config.getProperties().put(AvailableSettings.SHOW_SQL,"true");
    config.getProperties().put(AvailableSettings.FORMAT_SQL,"true");
    config.getProperties().put(AvailableSettings.HBM2DDL_AUTO,"update");
    config.getProperties().put(AvailableSettings.DEFAULT_SCHEMA,"public");
    config.getProperties().put(AvailableSettings.STATEMENT_BATCH_SIZE,"3000");
    config.getProperties().put(AvailableSettings.USE_SECOND_LEVEL_CACHE,"true");
    config.getProperties().put(AvailableSettings.CACHE_REGION_FACTORY,"org.hibernate.cache.ehcache.EhCacheRegionFactory");
    config.getProperties().put(AvailableSettings.ORDER_UPDATES,"true");
    config.getProperties().put(AvailableSettings.ORDER_INSERTS,"true");
    config.getProperties().put(AvailableSettings.MAX_FETCH_DEPTH,"1");
    config.setNamingStrategy(new ImprovedNamingStrategy());

    Map<String, DataSource> dataSources = new HashMap<String, DataSource>();
    DataSource dataSource1 = createDataSource("jdbc:postgresql://localhost/tenant1","postgres","postgres");
    DataSource dataSource2 = createDataSource("jdbc:postgresql://localhost/tenant2","postgres","postgres");

    dataSources.put("tenant1",dataSource1);
    dataSources.put("tenant2",dataSource2);

    MultiTenantConnectionProviderImpl multiTenantConnectionProvider = new MultiTenantConnectionProviderImpl(dataSources);
    MultiTenantIdentifierResolver currentTenantIdentifierResolver = new MultiTenantIdentifierResolver();
    config.getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER,multiTenantConnectionProvider);
    config.getProperties().put(AvailableSettings.MULTI_TENANT,MultiTenancyStrategy.DATABASE);
    config.getProperties().put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER,currentTenantIdentifierResolver);
    // JPA annotated classes
    config.addPackage("com.sd.entity");
    config.addAnnotatedClass(User.class);
    serviceRegistry = (ServiceRegistryImplementor)new ServiceRegistryBuilder().applySettings(config.getProperties())
        .addService(MultiTenantConnectionProvider.class,multiTenantConnectionProvider).buildServiceRegistry();

    sessionFactory = (SessionFactoryImplementor)config.buildSessionFactory(serviceRegistry);
  }

  private DataSource createDataSource(String url, String userName, String password)
  {
    final String driver = "org.postgresql.Driver";
    final String validationQuery = "SELECT 1 ";

    final int minIdle = 3;
    final int maxIdle = 3;
    final int maxActive = 10;
    final long maxWait = 6000;
    final boolean removeAbandoned = true;
    final boolean logAbandoned = true;
    final boolean testOnBorrow = true;
    final boolean testOnReturn = false;
    final boolean testWhileIdle = false;
    final long timeBetweenEvictionRunsMillis = 30000;
    final long minEvictableIdleTimeMillis = 30000;

    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(driver);
    dataSource.setUsername(userName);
    dataSource.setPassword(password);
    dataSource.setValidationQuery(validationQuery);
    dataSource.setUrl(url);
    dataSource.setMaxIdle(minIdle);
    dataSource.setMaxIdle(maxIdle);
    dataSource.setMaxActive(maxActive);
    dataSource.setMaxWait(maxWait);
    dataSource.setRemoveAbandoned(removeAbandoned);
    dataSource.setLogAbandoned(logAbandoned);
    dataSource.setTestOnBorrow(testOnBorrow);
    dataSource.setTestOnReturn(testOnReturn);
    dataSource.setTestWhileIdle(testWhileIdle);
    dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
    dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
    return dataSource;
  }

  protected Session getNewSession(String tenant)
  {
    return sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
  }

  @Test
  public void testTableBasedMultiTenancy()
  {
    // try getting a new session explicitly providing the tenant identifier
    Session session = getNewSession("tenant1");
    session.beginTransaction();
    User user = (User)session.load(User.class,1l);
    System.out.println("************************* (" + user.getEmail() + " ) ***********************************");
    session.getTransaction().commit();
    session.close();
  }

}

这段代码在使用 sessionFactory 的 hibernate 中运行良好。我想将此代码转换为使用 entityManager 而不是 sessionFactory,因为我将 spring data jpa 与 HibernateJpaVendorAdapter 一起使用。

如果您有 spring data jpa 和多租户(每个租户的单独数据库)的任何示例/示例,请分享或提供信息。

提前致谢。我们将非常感谢您的帮助。

【问题讨论】:

    标签: hibernate jpa postgresql-9.1 spring-data


    【解决方案1】:

    如果我的理解是正确的,您只需在您的 persistence.xml 中创建持久性单元:

    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">
    <persistence-unit name="test_persistance_unit"
        transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
    
        <properties>
            <property name="hibernate.connection.url"
                value="jdbc:postgresql://localhost:5432/db1" />
            <property name="hibernate.connection.username" value="postgres" />
            <property name="hibernate.connection.password" value="postgres" />
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="hibernate.show-sql" value="false" />
            <property name="hibernate.jdbc.batch_size" value="1000"/>                   
        </properties>
    </persistence-unit>
    
    <persistence-unit name="test_persistance_unit_2"
        transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
    
        <properties>
            <property name="hibernate.connection.url"
                value="jdbc:postgresql://localhost:5432/db2" />
            <property name="hibernate.connection.username" value="postgres" />
            <property name="hibernate.connection.password" value="postgres" />
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="hibernate.show-sql" value="false" />
            <property name="hibernate.jdbc.batch_size" value="1000"/>                   
        </properties>
    </persistence-unit>
    

    在此之后,您将需要拥有并使用 2 个 EntityManagerFactory(每个数据库一个)。

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("test_persistance_unit");
    EntityManagerFactory emf2 = Persistence.createEntityManagerFactory("test_persistance_unit_2");
    

    【讨论】:

    • 我不想创建多个实体管理器工厂。考虑如果我在每个数据库中有 500 多个实体和 500 多个数据库,那么将使用多少内存。每个数据库的结构都是相同的,所以我可以使用一个实体管理器工厂。顺便说一句,我已经这样做了。我会尽快发布我的解决方案。
    【解决方案2】:

    我已经完成了这个。我关注了https://community.jboss.org/message/855264?et=watches.email.thread

    我会尽快发布我的解决方案。

    【讨论】:

    • Sunny Dyal,如果你能在这里分享你的实现就好了
    【解决方案3】:

    这里有一个工作示例:http://blog.sandeepgupta.info/2014/07/making-application-multi-tenant-with.html

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2016-06-26
      • 2019-06-15
      • 2014-04-07
      • 2014-12-22
      • 2017-11-19
      • 2015-05-08
      • 1970-01-01
      • 2016-05-03
      • 2019-07-20
      相关资源
      最近更新 更多