简体   繁体   中英

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

Our application uses Spring/Hibernate for database access. We use multiple hibernate session factories ( hibernate3.LocalSessionFactoryBean ), because the data is in a number of separate databases. Each session factory is configured with a pooled datasource using 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?

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.

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. Then you will have a connection pool with C1 and 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.

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.

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? 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.


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". 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. 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.

Take a look at the following article for exemple (there are many on that subject): 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 ;)

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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