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,因爲我在HibernateJpaVendorAdapter中使用了spring數據jpa。Spring Data JPA,Hibernate Vendor,Multi-Tenancy和Postgres SQL
如果您有彈簧數據jpa和多租戶的任何示例/樣本(每個承租人單獨的數據庫),請分享或提供信息。
在此先感謝。您的幫助將受到高度讚賞。
我不想創建多個實體管理器工廠。考慮如果每個數據庫和500+數據庫中有500多個實體,那麼將使用多少內存。每個數據庫的結構相同,因此我可以使用一個實體管理器工廠。順便說一句,我已經完成了這一點。我會盡快發佈我的解決方案。 –