简体   繁体   English

我可以通过Spring / Hibernate / c3p0将一个池化数据源用于多个数据库吗?

[英]Can I use one pooled datasource for multiple databases with Spring/Hibernate/c3p0?

Our application uses Spring/Hibernate for database access. 我们的应用程序使用Spring / Hibernate进行数据库访问。 We use multiple hibernate session factories ( hibernate3.LocalSessionFactoryBean ), because the data is in a number of separate databases. 我们使用多个hibernate会话工厂( hibernate3.LocalSessionFactoryBean ),因为数据位于多个单独的数据库中。 Each session factory is configured with a pooled datasource using c3p0 ( c3p0.ComboPooledDataSource ). 每个会话工厂都使用c3p0( c3p0.ComboPooledDataSource )配置有池化数据源。

As it happens, the databases all reside on the same db server. 碰巧的是,所有数据库都驻留在同一数据库服务器上。 Our issue is that we end up with a number of db connection pools, all connecting into the same server. 我们的问题是,最终我们有许多数据库连接池,所有连接池都连接到同一服务器上。 Is there any way of sharing one pooled datasource for access to multiple databases on the same server? 有什么方法可以共享一个池化数据源以访问同一服务器上的多个数据库? Is it possible to configure the jdbcUrl at the session factory level, instead of at the datasource level? 是否可以在会话工厂级别而不是数据源级别配置jdbcUrl

Or is this not a real issue in practice? 还是这不是实际的问题? Is it perfectly ok to have multiple db connection pools configured? 配置多个数据库连接池是否完全可以?

One Connection connects to one DB. 一个连接连接到一个数据库。

If you have 2 databases, DB1 and DB2, and want a connection pool, you need to have prepared connections for both databases. 如果您有两个数据库DB1和DB2,并且想要一个连接池,则需要为两个数据库准备连接。

If you have 1 connection per pool actually, C1 and C2 (i know you have more but it's the same...) For sure it would be possible to put these both connections in the same connection pool. 如果每个池实际上有1个连接,则C1和C2(我知道您有更多连接,但相同...)当然可以将这两个连接放在同一个连接池中。 Then you will have a connection pool with C1 and C2. 然后,您将拥有一个包含C1和C2的连接池。 What do you expect from your connection pool? 您对连接池有什么期望? For me -> to be able to give you random already prepared connection that you can directly use, without the overhead of creation a new connection. 对我来说->能够为您提供可以直接使用的随机已准备好的连接,而无需创建新连接。

Now guess what, if you have both C1 and C2 in your unique pool, you simply can't get a "random" connection since they do not belong to the same database... Thus you'll have the overhead of checking if the connection returned points to the expected database, or you'll have 50% chances to execute request R1 on DB2. 现在猜想是什么,如果您的唯一池中同时包含C1和C2,您将根本无法获得“随机”连接,因为它们不属于同一数据库...因此,您将需要检查是否存在连接返回指向期望的数据库,否则您将有50%的机会在DB2上执行请求R1。

So yes it is possible, you could simple make your own implementation of a connection pool that just use 2 child connection pools CP1 and CP2 and that will randomly use the getConnection from one of these child connection pools randomly, but you'll have to check you use the right connection pool afterward so you'd better keep separated 2 different connection pools. 因此,是的,有可能,您可以简单地自己创建一个连接池,该连接池仅使用两个子连接池CP1和CP2,并随机使用这些子连接池之一中的getConnection,但是您必须检查您在以后使用正确的连接池,因此最好将两个不同的连接池分开。

I don't know why you only want one connection pool. 我不知道为什么您只想要一个连接池。 Perhaps you want to be able to tell your app "there are 100 connections for all connection pools" and you'd like your app to automagically set an optimized number of connection in each pool you have? 也许您想告诉您的应用“所有连接池有100个连接”,并且希望您的应用自动在每个池中设置优化的连接数? It seems possible to me but i don't know if there is an already existing generic implementation for that, perhaps you can do a connection pool wrapper that will share between all existing pools the average % of connections used and then adjust the pools sizes or something like that... 在我看来,这是可能的,但我不知道是否已经存在通用的实现,也许您可​​以做一个连接池包装器,该包装器将在所有现有池之间共享使用的平均连接百分比,然后调整池的大小或像那样的东西


For me it is totally ok to have multiple connection pools in your application. 对我来说,在您的应用程序中拥有多个连接池是完全可以的。 As well as it is totally ok to use 2 different databases in the same application (Oracle + MongoDB or something like that), it is also totally ok to use 2 connection pools that use 2 Oracle database schemas on the same server, and even if both databases have the exact same tables. 在同一应用程序(Oracle + MongoDB或类似的应用程序)中使用2个不同的数据库完全可以,在同一服务器上使用2个使用2个Oracle数据库模式的连接池也是完全可以的,即使这两个数据库具有完全相同的表。


You should look at multitenancy strategies for SaaS applications with multiple customers (B2B generally): - One is to have one DB for every customers, and to have each table having a column "customer_id". 您应该查看具有多个客户(通常为B2B)的SaaS应用程序的多租户策略:-一种是为每个客户拥有一个DB,并且每个表都具有“ customer_id”列。 It's easier to maintain but there are more rows on the tables (but obviously you index that customer_id column) - The other is perhaps what you do: have one database/datasource/connectionpool/sessionfactory per customer, and every database will have the same tables. 维护起来更容易,但是表上有更多行(但显然您为该customer_id列建立了索引)-另一个可能是您要做的:每个客户拥有一个数据库/数据源/连接池/会话工厂,并且每个数据库都具有相同的表。 Eventually you'll have some mecanism like a "customized main sessionfactory" which will use a ThreadLocal (set by some credential filter?) that store the customerId to select the appropriate child sessionfactory. 最终,您将具有某种“机制”,例如“定制的主sessionfactory”,它将使用ThreadLocal(由某些凭据过滤器设置吗?)存储customerId来选择适当的子sessionfactory。

Take a look at the following article for exemple (there are many on that subject): http://relation.to/Bloggers/MultitenancyInHibernate 请看以下示例文章(关于该主题的文章很多): 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
    }
}

It's almost what i told you except that here there is a dynamic connection provider instead of a dynamic session provider. 除了告诉我这里有一个动态连接提供程序而不是一个动态会话提供程序外,几乎是我告诉过您的。 (Tenant here = Customer in my exemple) (这里的租户=以我的客户为例)

You can notice that there is no connection pooling in this exemple but you sure can implement your own PooledMyTenantAwareConnectionProvider ;) 您可能会注意到此示例中没有连接池,但是您可以实现自己的PooledMyTenantAwareConnectionProvider;)

Good luck. 祝好运。

I don't think you can do that. 我认为您无法做到。 And I don't think I would do that. 而且我认为我不会那样做。 Either treat them as separate databases, or as one. 要么将它们视为独立的数据库,要么视为一个数据库。

If they're separate databases they got different connection pools and needs to be managed by JTA, or you need to design your entire system for transaction failures between these bases. 如果它们是单独的数据库,则它们具有不同的连接池,需要由JTA管理,或者您需要针对这些基础之间的事务失败设计整个系统。

If they're to be treated as one; 如果将它们视为一体; you can (if you're using Oracle) create one connection pool, then use alias and grants to enable that single connection to write to the two other databases. 您可以(如果使用的是Oracle)创建一个连接池,然后使用别名和授权来使该单个连接写入其他两个数据库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM