我们的应用程序使用Spring / Hibernate进行数据库访问。我们使用多个hibernate会话工厂(hibernate3.LocalSessionFactoryBean
),因为数据位于许多单独的数据库中。每个会话工厂都使用c3p0(c3p0.ComboPooledDataSource
)配置了池数据源。
实际上,数据库都驻留在同一个数据库服务器上。我们的问题是我们最终得到了许多数据库连接池,它们都连接到同一台服务器。有没有办法共享一个池数据源来访问同一台服务器上的多个数据库?是否可以在会话工厂级别而不是在数据源级别配置jdbcUrl
?
或者这在实践中不是一个真正的问题吗?是否可以配置多个数据库连接池?
答案 0 :(得分:2)
一个连接连接到一个数据库。
如果您有2个数据库,DB1和DB2,并且需要连接池,则需要为两个数据库准备好连接。
如果你实际上每个游泳池有1个连接,C1和C2(我知道你有更多,但它是相同的......) 当然,可以将这两个连接放在同一个连接池中。 然后你将有一个C1和C2的连接池。 您对连接池的期望是什么?对我来说 - >能够为您提供可以直接使用的随机已准备好的连接,而无需创建新连接的开销。
现在猜猜看,如果你的唯一池中有C1和C2,你根本就无法获得“随机”连接,因为它们不属于同一个数据库...因此你将有开销检查返回的连接是否指向预期的数据库,或者您有50%的机会在DB2上执行请求R1。
所以是的,有可能,您可以简单地自己实现一个只使用2个子连接池CP1和CP2的连接池,并且随机使用其中一个子连接池中的getConnection,但是你会必须检查你之后使用正确的连接池,这样你最好保持分开的2个不同的连接池。
我不知道你为什么只想要一个连接池。也许您希望能够告诉您的应用“所有连接池有100个连接”,并且您希望您的应用在您拥有的每个池中自动设置优化连接数?对我来说似乎是可能的,但我不知道是否存在已经存在的通用实现,也许你可以做一个连接池包装器,它将在所有现有池之间共享所用连接的平均百分比,然后调整池大小或类似的东西...
对我来说,在您的应用程序中拥有多个连接池是完全可以的。 除了在同一个应用程序中使用2个不同的数据库(Oracle + MongoDB或类似的东西)完全没问题之外,在同一台服务器上使用2个Oracle数据库模式的连接池也是完全可以的,即使两个数据库都有完全相同的表格。
您应该了解具有多个客户的SaaS应用程序的多租户策略(B2B一般): - 一个是为每个客户提供一个数据库,并让每个表都有一个“customer_id”列。它更容易维护,但表上有更多行(但显然你索引customer_id列) - 另一个可能是你做的:每个客户有一个数据库/数据源/连接池/ sessionfactory,每个数据库都有相同的表。最终你会有一些像“自定义主会话”这样的机制,会使用ThreadLocal(由某些凭证过滤器设置?)来存储customerId以选择适当的子会话。
看一下以下文章的例子(该主题有很多): http://relation.to/Bloggers/MultitenancyInHibernate
public class MyTenantAwareConnectionProvider implements ConnectionProvider {
public static final String BASE_JNDI_NAME_PARAM = "MyTenantAwareConnectionProvider.baseJndiName";
private String baseJndiName;
public void configure(Properties props) {
baseJndiName = props.getProperty( BASE_JNDI_NAME_PARAM );
}
public Connection getConnection() throws SQLException {
final String tenantId = TenantContext.getTenantId()
final String tenantDataSourceName = baseJndiName + '/' + tenantId;
DataSource tenantDataSource = JndiHelper.lookupDataSource( tenantDataSourceName );
return tenantDataSource.getConnection();
}
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
public boolean supportsAggressiveRelease() {
// so long as the tenant identifier remains available in TL throughout, we can
return true;
}
public close() {
// currently nothing to do here
}
}
这几乎是我告诉你的,除了这里有动态连接提供程序而不是动态会话提供程序。 (租客在这里=客户在我的例子中)
您可以注意到此示例中没有连接池,但您确定可以实现自己的PooledMyTenantAwareConnectionProvider;)
祝你好运。答案 1 :(得分:0)
我认为你不能这样做。而且我不认为我会这样做。要么将它们视为单独的数据库,要么将它们视为一个数据库。
如果他们分离数据库,他们会得到不同的连接池,并且需要由JTA管理,或者您需要设计整个系统以解决这些基础之间的事务失败。
如果他们被视为一个人;您可以(如果您正在使用Oracle)创建一个连接池,然后使用别名和授权来启用该单个连接以写入另外两个数据库。