0

我将 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。请帮我。谢谢。

4

3 回答 3

1

我懒得修改 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 来使用它。

于 2012-07-28T03:36:02.063 回答
0

在 OSGi 中这样工作(使用 Java EE 模式)会让你陷入很多痛苦,因为许多 Java EE 模式都是反模块化的,它们需要对类路径的深入可见性。由于 OSGi 具有很强的模块化,这不能很好地工作,需要像 Context Classloader 和其他容易出错的东西,最终通常不起作用。OSGi µservices 被发明来以模块化和更优雅的方式处理此类问题。

OSGi-JDBC 规范(第 125 章)指定了如何在 µservice 世界中使用 JDBC:驱动程序包应该注册一个org.osgi.service.jdbc.DataSourceFactory服务。使用此服务,创建您的池化数据源是微不足道的。我从经验中知道 H2 数据库是开箱即用的(感谢 H2 的家伙!很棒的产品)。幸运的是,Ops4j 这里有一个项目,为 MySql 提供了一个适配器。由于 MySql 不是作为 OSGi 捆绑包提供的标准,您可能会在这里查看

因此,在安装 MySql Driver 和 PAX JDBC MySql Adapter 之后,您现在可以以真正模块化的方式使用 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)”,这允许您动态连接服务。

于 2013-07-29T07:16:30.030 回答
0

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

于 2012-07-27T17:17:34.357 回答