minhcong minhcong - 6 months ago 28
SQL Question

MySQL, c3p0 and Apache Felix integration

I integrate MySQL into Apache Felix.
First, I use bndtools to generate MySQL bundle and c3p0 bundle. Then I add them all into my Apache Felix environment.
I create a class for connection pool like below:


public final class C3P0Manager {

private static C3P0Manager instance;
private DataSource pooled;

private C3P0Manager() {
// Of course, it is better to put all properties into a configuration file.
// I just list them here for easy reading.

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver"));
cpds.setJdbcUrl("jdbc:mysql://localhost/my-database?autoReconnect=true&characterSetResults=UTF-8&characterEncoding=UTF-8&useUnicode=yes");
cpds.setUser("user");
cpds.setPassword("password");
cpds.setInitialPoolSize(3);
cpds.setMaxPoolSize(15);
cpds.setMaxIdleTime(1800);
cpds.setAutoCommitOnClose(true);
pooled(cpds);
}

public static C3P0Manager instance() throws Exception {
if (instance == null) {
instance = new C3P0Manager();
}
return instance;
}

public DataSource getPooled() throws SQLException {
return pooled;
}
}


It works fine if I run JUnit test.
But failed when running on my Apache Felix bundle with exception message.
Usage in Activator class:



Class.forName("com.mysql.jdbc.Driver");
DataSource pooled = C3P0Manager.instance().getPooled();
Connection con = pooled.getConnection();
PreparedStatement stmt = null;
ResultSet rs = null;
int total;

try {
stmt = con.prepareStatement("SELECT count(*) FROM users", Statement.NO_GENERATED_KEYS);
rs = stmt.executeQuery();
if (rs.next()) {
total = rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
System.out.println("total = " + total);



Error messages:



java.sql.SQLException: Connections could not be acquired from the underlying database!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:529)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
...
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
...



MySQL works if I just use (without c3p0):



Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/my-database?autoReconnect=true&characterSetResults=UTF-8&characterEncoding=UTF-8&useUnicode=yes","user","password");
Statement statement = connect.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT count(*) FROM users");



So I think the problem is due to c3p0. Please help me. Thanks.

Answer

I am lazy to modify c3p0 source and build new c3p0 bundle version again :). So I try Apache DBCP bundle instead:

org.apache.servicemix.bundles.commons-pool-1.5.4
org.apache.servicemix.bundles.commons-dbcp-1.4.0
(dbcp needs pool to work)

It is OK to CRUD MySQL database.

If anyone want to use those bundles, here they are:

http://mvnrepository.com/artifact/org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-pool
http://mvnrepository.com/artifact/org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-dbcp

When I have time, I will take a look at bonecp if someone already builds a bundle for it. Or modify c3p0 to use it.