我将MySQL集成到Apache Felix中 . 首先,我使用bndtools生成MySQL bundle和c3p0 bundle . 然后我将它们全部添加到我的Apache Felix环境中 . 我为连接池创建了一个类,如下所示:
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;
}
}
如果我运行JUnit测试,它工作正常 . 但是在我的Apache Felix捆绑包上运行异常消息时失败了 . 在Activator类中的用法:
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);
错误消息:
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)
...
如果我只使用(没有c3p0),MySQL可以工作:
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");
所以我认为问题是由于c3p0 . 请帮我 . 谢谢 .
3 回答
我懒得修改c3p0源并再次构建新的c3p0包版本:) . 所以我尝试使用Apache DBCP包:
CRUD MySQL数据库是可以的 .
如果有人想要使用这些捆绑包,这里它们是:
当我有时间的时候,如果有人已经为它构建了一个包,我会看一下 . 或者修改c3p0以使用它 .
请检查您的日志 . 在上面显示的异常之前,c3p0将记录堆栈跟踪,详细说明至少有一次尝试从数据库获取Connection失败 . 如果将日志记录级别设置为FINE(如果需要特定的 Logger ,请使用com.mchange.v2.resourcepool.BasicResourcePool),您将看到记录的每个失败尝试 . 如果将日志级别保留为常规INFO(或WARN),则只会在失败尝试的“回合”中看到最终失败的尝试(默认情况下,尝试失败30次,重试延迟为1秒) . 如果您一直在登录INFO,那么您应该能够在日志中找到这些例外 .
在OSGi中这样工作(使用Java EE模式)正在为您带来许多痛苦,因为许多Java EE模式都是反模块化的,它们需要深入了解类路径 . 由于OSGi具有强大的模块性,因此不能很好地工作,需要像Context Classloader这样的黑客以及其他容易出错的东西,这些东西最终通常都不起作用 . 发明了OSGiμservices来处理这种类型的模块化问题并且更加优雅 .
OSGi-JDBC规范(第125章)规定了如何在μservice世界中使用JDBC:驱动程序包应该注册org.osgi.service.jdbc.DataSourceFactory服务 . 使用此服务,创建合并的数据源非常简单 . 我从经验中知道H2数据库开箱即用(感谢H2家伙!很棒的产品) . 幸运的是,Ops4j has a project here为MySql提供了一个适配器 . 由于MySql不是标准的OSGi包,你可能看起来像here
因此,在安装MySql驱动程序和PAX JDBC MySql Adapter之后,您现在可以以真正的模块化方式使用DataSource:
注意这也如何从代码,单例,静态(全局变量)和动态类加载中删除MySql依赖项 . 当然,如果您生成依赖于MySQL的SQL,您可以将其显式化 . 您可以像这样使用
@Reference
:或者,更好的是,您允许应用程序的部署者使用Configuration Admin进行设置 . 只需将DataSourceFactory.target属性设置为“(osgi.jdbc.driver.name = mysql)”,即可动态连接服务 .