【发布时间】:2014-02-09 00:37:47
【问题描述】:
我正在尝试设置一个多租户 Web 应用程序,(理想情况下)可以同时使用数据库分离和模式分离的方法。虽然我将从模式分离开始。我们目前正在使用:
- 春季 4.0.0
- 休眠 4.2.8
- Hibernate-c3p0 4.2.8(使用 c3p0-0.9.2.1)
- 和 PostgreSQL 9.3(我怀疑它对整体架构真的很重要)
我主要关注this thread(因为@Transactional 的解决方案)。但是我在实施MultiTenantContextConnectionProvider 时有点迷失了。 SO上也有this similar question在这里问过,但是有些方面我想不通:
1) 连接池会发生什么?我的意思是,它是由 Spring 还是 Hibernate 管理的?我猜想ConnectionProviderBuilder - 或建议 - 它的任何实现,Hibernate 都是管理它的人。
2)Spring不管理连接池是一种好方法吗?或者 Spring 是否有可能管理它?
3)这是未来实现数据库和模式分离的正确途径吗?
任何 cmets 或描述都非常感谢。
application-context.xml
<beans>
...
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="c3p0DataSource" />
</bean>
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="org.postgresql.Driver" />
... other C3P0 related config
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan" value="com.webapp.domain.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.default_schema">public</prop>
<prop key="hibernate.multiTenancy">SCHEMA</prop>
<prop key="hibernate.tenant_identifier_resolver">com.webapp.persistence.utility.CurrentTenantContextIdentifierResolver</prop>
<prop key="hibernate.multi_tenant_connection_provider">com.webapp.persistence.utility.MultiTenantContextConnectionProvider</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="autodetectDataSource" value="false" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
...
</beans>
CurrentTenantContextIdentifierResolver.java
public class CurrentTenantContextIdentifierResolver implements CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
return CurrentTenantIdentifier; // e.g.: public, tid130, tid456, ...
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
MultiTenantContextConnectionProvider.java
public class MultiTenantContextConnectionProvider extends AbstractMultiTenantConnectionProvider {
// Do I need this and its configuratrion?
//private C3P0ConnectionProvider connectionProvider = null;
@Override
public ConnectionProvider getAnyConnectionProvider() {
// the main question is here.
}
@Override
public ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
// and of course here.
}
}
编辑
关于@ben75的the answer:
这是MultiTenantContextConnectionProvider 的新实现。它不再扩展AbstractMultiTenantConnectionProvider。它宁可实现MultiTenantConnectionProvider,以便能够返回[Connection][4] 而不是[ConnectionProvider][5]
public class MultiTenantContextConnectionProvider implements MultiTenantConnectionProvider, ServiceRegistryAwareService {
private DataSource lazyDatasource;;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
lazyDatasource = (DataSource) lSettings.get( Environment.DATASOURCE );
}
@Override
public Connection getAnyConnection() throws SQLException {
return lazyDatasource.getConnection();
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
}
return connection;
}
}
【问题讨论】:
-
了解您为什么要这样做和/或您的要求/顾虑是什么(即合规性、性能、卖点)会很有用。如今,使用“云”,许多人只是通过启动单独的映像来解决多租户问题,因此具有真正的分离,这通常是出于合规性原因所必需的,因此您不需要
DataSource级别的多租户。另一种选择是拥有一个能够感知多租户并根据性能原因对您的应用程序进行分区/分片的大型架构。 -
@AdamGent 我不打算为每个客户使用单独的实例的主要原因是我们的目标是 10K-50K+ 客户。据我所知,拥有这么多“单独的实例”比通过单实例应用程序的负载平衡、多租户集群拆分它们的成本要高得多。对于您评论的第二部分,为了灵活起见,我们将为数据层提供替代方法。如果客户想要一个单独的数据库,并且他们愿意为它支付额外的费用/月,那就这样吧。
标签: spring hibernate postgresql multi-tenant c3p0