【问题标题】:MySQL, c3p0 and Apache Felix integrationMySQL、c3p0 和 Apache Felix 集成
【发布时间】:2012-07-26 09:27:48
【问题描述】:

我将 MySQL 集成到 Apache Felix 中。 首先,我使用 bndtools 生成 MySQL bundle 和 c3p0 bundle。然后我将它们全部添加到我的 Apache Felix 环境中。 我为连接池创建了一个类,如下所示:

公共最终类 C3P0Manager { 私有静态 C3P0Manager 实例; 私有数据源池; 私人 C3P0Manager() { // 当然,最好把所有的属性都放到一个配置文件中。 // 我只是在这里列出它们以方便阅读。 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("用户"); cpds.setPassword("密码"); cpds.setInitialPoolSize(3); cpds.setMaxPoolSize(15); cpds.setMaxIdleTime(1800); cpds.setAutoCommitOnClose(true); 汇集(cpds); } 公共静态 C3P0Manager 实例()抛出异常 { 如果(实例==空){ 实例 = 新 C3P0Manager(); } 返回实例; } 公共数据源 getPooled() 抛出 SQLException { 归集归还; } }

如果我运行 JUnit 测试,它工作正常。 但是在我的 Apache Felix 捆绑包上运行时失败,出现异常消息。 在 Activator 类中的用法:

Class.forName("com.mysql.jdbc.Driver"); DataSource pooled = C3P0Manager.instance().getPooled(); 连接 con = pooled.getConnection(); PreparedStatement stmt = null; 结果集 rs = null; 整数; 尝试 { stmt = con.prepareStatement("SELECT count(*) FROM users", Statement.NO_GENERATED_KEYS); rs = stmt.executeQuery(); 如果(rs.next()){ 总计 = rs.getInt(1); } } 捕捉(异常 e){ e.printStackTrace(); } 最后 { 尝试 { rs.close(); stmt.close(); } 捕捉(异常前){ ex.printStackTrace(); } } System.out.println("总计 = " + 总计);

错误信息:

java.sql.SQLException:无法从底层数据库获取连接! 在 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106) 在 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:529) 在 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128) ... 原因:com.mchange.v2.resourcepool.CannotAcquireResourceException:ResourcePool 无法从其主工厂或源获取资源。 在 com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319) 在 com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557) 在 com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477) 在 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525) ...

如果我只使用(不带 c3p0),MySQL 就可以工作:

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

所以我认为问题是由于c3p0。请帮我。谢谢。

【问题讨论】:

  • 我也尝试过 DataSource 但仍然失败。 DataSource unpooled = DataSources.unpooledDataSource("jdbc:mysql://localhost/my-database?autoReconnect=true&characterSetResults=UTF-8&characterEncoding=UTF-8&useUnicode=yes", "user", "password"); DataSource pooled = DataSources.pooledDataSource( unpooled );

标签: mysql osgi c3p0


【解决方案1】:

在 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 适配器后,您现在可以以真正模块化的方式使用 DataSource:

@Component
public class DataSourceDemo {
   DataSource ds;

   @Activate
   void start() {
       Connection con = ds.getConnection();
       PreparedStatement stmt = con.prepareStatement("SELECT count(*) FROM users", Statement.NO_GENERATED_KEYS);
       ResultSet rs = stmt.executeQuery();
       if (rs.next()) {
        System.out.println(rs.getInt(1));
       }
   }

   @Reference
   void setDataSourceFactory( DataSourceFactory dsf ) throws Exception {
     ds = dsf.createDataSource();
   }
}

请注意,这还如何从您的代码、单例、静态(全局变量)和动态类加载中删除 MySql 依赖项。当然,如果您生成依赖于 MySQL 的 SQL,您可以明确说明这一点。您可以像这样使用@Reference

 @Reference(target="(osgi.jdbc.driver.name=mysql)")

或者,更好的是,您允许应用程序的部署者使用配置管理员进行设置。只需将 DataSourceFactory.target 属性设置为“(osgi.jdbc.driver.name=mysql)”,这允许您动态连接服务。

【讨论】:

【解决方案2】:

我懒得修改 c3p0 源代码并再次构建新的 c3p0 捆绑版本 :)。 所以我改用 Apache DBCP 包:

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

对 MySQL 数据库进行 CRUD 即可。

如果有人想使用这些捆绑包,请点击这里:

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

当我有时间时,如果有人已经为它构建了一个捆绑包,我会看看bonecp。 或者修改c3p0来使用。

【讨论】:

【解决方案3】:

请检查您的日志。在您在上面显示的异常之前,c3p0 将记录堆栈跟踪,详细说明至少一次尝试从数据库获取连接的失败。如果您将日志记录级别设置为 FINE(如果您需要特定的记录器,请使用 com.mchange.v2.resourcepool.BasicResourcePool),您将看到记录的每次失败尝试。如果您将日志级别保留在常规 INFO(或 WARN),您将只看到“一轮”失败尝试中的最后一次失败尝试(默认情况下 30 次失败尝试,重试延迟为 1 秒)。如果您一直在 INFO 登录,您应该已经能够在您的日志中找到这些异常。

【讨论】:

  • 谢谢,史蒂夫沃尔德曼。我打开 c3p0 记录器。它说: 无法加载 driverClass com.mysql.jdbc.Driverjava.lang.ClassNotFoundException: com.mysql.jdbc.Driver not found by c3p0-0.9.1.2 [22] at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation( BundleWiringImpl.java:1460) 在 org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72) 在 org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843) 在 java. lang.ClassLoader.loadClass(Unknown Source)
  • 类加载器查找MySQL似乎有问题。我不知道如何解决它,因为我是 Apache Felix 世界的新手。
  • 根据 [link]stackoverflow.com/questions/2198928/… 和 [link]stackoverflow.com/questions/9911587/…,当 c3p0 为 db 连接创建新线程时,该线程不共享相同的类加载器上下文。它导致 MySQL class not found 异常。我该如何解决?
  • 我对 Apache Felix 了解不多,但可以尝试的一件简单的事情是将包含 mysql 驱动程序的 jar 文件放在与 c3p0 jar 文件相同的位置。 [c3p0-0.9.2pre4,最新版本,需要两个 jar 文件。] 或者,您可以将 mysql jar 文件放在某些“根”类加载器可以找到的位置,例如 lib/ext 目录 [docs.oracle.com/javase/tutorial/ext/basics/install.html ],大多数线程应该能够看到。
  • 我将 c3p0 和 MySQL 组合成一个包,但问题仍然存在。根本原因是当 c3p0 创建一个新线程时,该线程访问了除 OSGi 包上下文之外的不同类加载器上下文,并且找不到 MySQL 的类路径。我改用 dbcp 并且它可以工作。请参阅我的以下消息。谢谢,史蒂夫!
猜你喜欢
  • 2014-09-09
  • 1970-01-01
  • 2017-07-11
  • 2019-11-29
  • 1970-01-01
  • 2011-11-03
  • 2017-10-25
  • 2016-10-13
  • 1970-01-01
相关资源
最近更新 更多