首页 文章

MySQL,c3p0和Apache Felix集成

提问于
浏览
0

我将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 回答

  • 0

    我懒得修改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)
    

    CRUD MySQL数据库是可以的 .

    如果有人想要使用这些捆绑包,这里它们是:

    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
    

    当我有时间的时候,如果有人已经为它构建了一个包,我会看一下 . 或者修改c3p0以使用它 .

  • 1

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

  • 0

    在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:

    @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)")
    

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

相关问题