我可以使用Spring / Hibernate / c3p0为多个数据库使用一个池数据源吗?

时间:2011-12-15 12:39:47

标签: hibernate spring datasource c3p0

我们的应用程序使用Spring / Hibernate进行数据库访问。我们使用多个hibernate会话工厂(hibernate3.LocalSessionFactoryBean),因为数据位于许多单独的数据库中。每个会话工厂都使用c3p0(c3p0.ComboPooledDataSource)配置了池数据源。

实际上,数据库都驻留在同一个数据库服务器上。我们的问题是我们最终得到了许多数据库连接池,它们都连接到同一台服务器。有没有办法共享一个池数据源来访问同一台服务器上的多个数据库?是否可以在会话工厂级别而不是在数据源级别配置jdbcUrl

或者这在实践中不是一个真正的问题吗?是否可以配置多个数据库连接池?

2 个答案:

答案 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)创建一个连接池,然后使用别名和授权来启用该单个连接以写入另外两个数据库。