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

Posted

技术标签:

【中文标题】我可以使用 Spring/Hibernate/c3p0 为多个数据库使用一个池数据源吗?【英文标题】:Can I use one pooled datasource for multiple databases with Spring/Hibernate/c3p0? 【发布时间】:2012-01-21 03:48:28 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

我认为你做不到。而且我不认为我那样做。要么将它们视为单独的数据库,要么作为一个数据库。

如果它们是独立的数据库,它们有不同的连接池并且需要由 JTA 管理,或者您需要设计整个系统以应对这些库之间的事务失败。

如果它们被视为一体;您可以(如果您使用 Oracle)创建一个连接池,然后使用别名和授权使该单个连接能够写入其他两个数据库。

【讨论】:

【参考方案2】:

一个连接连接到一个数据库。

如果您有 2 个数据库 DB1 和 DB2,并且想要一个连接池,则需要为这两个数据库准备好连接。

如果每个池实际上有 1 个连接,C1 和 C2(我知道你有更多,但它是一样的......) 当然可以将这两个连接放在同一个连接池中。 然后您将拥有一个包含 C1 和 C2 的连接池。 您对连接池有什么期望?对我来说 -> 能够为您提供可以直接使用的随机已经准备好的连接,而无需创建新连接的开销。

现在你猜怎么着,如果你的唯一池中同时有 C1 和 C2,你根本无法获得“随机”连接,因为它们不属于同一个数据库......因此你将有检查返回的连接是否指向预期的数据库,否则您将有 50% 的机会在 DB2 上执行请求 R1。

所以是的,有可能,您可以简单地自己实现一个连接池,该连接池仅使用 2 个子连接池 CP1 和 CP2,并且会随机使用这些子连接池之一中的 getConnection,但您会之后必须检查您是否使用了正确的连接池,因此您最好将两个不同的连接池分开。

我不知道你为什么只想要一个连接池。也许您希望能够告诉您的应用“所有连接池都有 100 个连接”,并且您希望您的应用在您拥有的每个池中自动设置优化的连接数?对我来说似乎可行,但我不知道是否已经存在通用实现,也许您可​​以做一个连接池包装器,它将在所有现有池之间共享使用的平均连接百分比,然后调整池大小或类似的东西...


对我来说,在您的应用程序中拥有多个连接池是完全可以的。 除了在同一个应用程序中使用 2 个不同的数据库(Oracle + MongoDB 或类似的东西)完全可以,在同一台服务器上使用 2 个使用 2 个 Oracle 数据库模式的连接池也是完全可以的,即使两个数据库都有完全相同的表。


您应该查看具有多个客户的 SaaS 应用程序的多租户策略(通常是 B2B): - 一种是为每个客户提供一个数据库,并让每个表都有一个“customer_id”列。它更容易维护,但表上有更多行(但显然你索引了 customer_id 列) - 另一个可能是您所做的:每个客户有一个数据库/数据源/连接池/会话工厂,每个数据库都有相同的表。最终,您将拥有一些机制,例如“自定义主 sessionfactory”,它将使用 ThreadLocal(由某些凭据过滤器设置?)存储 customerId 以选择适当的子 sessionfactory。

以以下文章为例(关于该主题的文章很多): 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 ;)

祝你好运。

【讨论】:

以上是关于我可以使用 Spring/Hibernate/c3p0 为多个数据库使用一个池数据源吗?的主要内容,如果未能解决你的问题,请参考以下文章

如果 C3P0 无法获得数据库连接,则 Tomcat 挂起

我可以同时使用 UIPageViewControllers 吗?

一旦我可以使用 XMPP 列出用户,我如何在这些用户之间实现聊天?

我可以在 ScriptEditor、SharePoint 中使用 Json 吗?

我可以使用啥图表来显示 Html 事件和操作

HTML5 本地存储 - 我可以为每个键存储多个值,如果不能,我可以使用啥替代方案?