Интеграция MySQL, c3p0 и Apache Felix

Я интегрирую MySQL в Apache Felix. Во-первых, я использую bndtools для создания пакета MySQL и пакета c3p0. Затем я добавляю их все в свою среду 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)
    ...

MySQL работает, если я просто использую (без 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");

Думаю, проблема в c3p0. Помогите, пожалуйста. Спасибо.


person cuongvm    schedule 27.07.2012    source источник
comment
Я также пробую DataSource, но все равно не смог. Источник данных unpooled = DataSources.unpooledDataSource (jdbc: mysql: // localhost / my-database? AutoReconnect = true & characterSetResults = UTF-8 & characterEncoding = UTF-8 & useUnicode = yes, user, password); Источник данных в пуле = Источники данных.pooledDataSource (не в пуле);   -  person cuongvm    schedule 27.07.2012


Ответы (3)


Мне лень модифицировать исходный код 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

Когда у меня будет время, я посмотрю на bonecp, если кто-то уже собирает для него бандл. Или измените c3p0, чтобы использовать его.

person cuongvm    schedule 28.07.2012
comment
Если вы сами нашли решение, не стесняйтесь принять свой ответ. - person Björn Pollex; 30.07.2012

Пожалуйста, проверьте свои журналы. До Исключения, которое вы показали выше, c3p0 регистрировал трассировки стека с подробным описанием по крайней мере одной неудачной попытки получить Соединение из базы данных. Если вы установите уровень ведения журнала FINE (если вам нужен конкретный регистратор, используйте com.mchange.v2.resourcepool.BasicResourcePool), вы увидите, что каждая неудачная попытка регистрируется. Если вы оставите свой уровень журнала на обычном INFO (или WARN), вы увидите только последнюю неудачную попытку в «раунде» неудачных попыток (по умолчанию 30 неудачных попыток с задержкой повтора в 1 секунду). Если вы заходили в INFO, вы уже должны найти эти исключения в своих журналах.

person Steve Waldman    schedule 27.07.2012
comment
Спасибо, Стив Уолдман. Включаю регистратор c3p0. В нем говорится: Не удалось загрузить driverClass com.mysql.jdbc.Driverjava.lang.ClassNotFoundException: com.mysql.jdbc.Driver не найден c3p0-0.9.1.2 [22] в org.apache.felix.framework.BundleWiringImpl.findClassOrResourceB BundleWiringImpl.java:1460) в org.apache.felix.framework.BundleWiringImpl.access $ 400 (BundleWiringImpl.java:72) в org.apache.felix.framework.BundleWiringImpl $ BundleClassLoader.loadClass (BundleWiringImpl). lang.ClassLoader.loadClass (Неизвестный источник) - person cuongvm; 27.07.2012
comment
Кажется, есть проблема с загрузчиком классов при поиске MySQL. Я не знаю, как это исправить, потому что я новичок в мире Apache Felix. - person cuongvm; 27.07.2012
comment
Согласно [ссылка] stackoverflow.com/questions/2198928/ и [ссылка] stackoverflow.com/questions/9911587/, когда c3p0 создает новый поток для подключения к базе данных, этот поток не использует один и тот же контекст загрузчика классов. Это вызывает исключение MySQL class not found. Как я могу это решить? - person cuongvm; 27.07.2012
comment
Я не очень много знаю об Apache Felix, но одна простая вещь, которую нужно попробовать, - это поместить файл jar, содержащий драйвер mysql, в то же место, что и файл (ы) jar c3p0. [c3p0-0.9.2pre4, последней версии, требуются два файла jar.] в качестве альтернативы вы можете разместить файл jar mysql там, где он будет найден каким-нибудь загрузчиком корневых классов, например, в каталоге lib / ext [docs.oracle.com/javase/tutorial/ext/basics/install.html ], которую должно видеть большинство потоков. - person Steve Waldman; 28.07.2012
comment
Я объединяю c3p0 и MySQL в связку, но проблема все еще существует. Основная причина заключается в том, что когда c3p0 создает новый поток, этот поток обращается к другому контексту загрузчика классов, отличному от контекста пакета OSGi, и не находит путь класса к MySQL. Вместо этого я использую dbcp, и он работает. См. Мое сообщение ниже. Спасибо, Стив! - person cuongvm; 28.07.2012

Подобная работа (с использованием шаблонов Java EE) в OSGi навлекает на вас множество страданий, поскольку многие шаблоны Java EE антимодульны, они требуют глубокой видимости пути к классу. Поскольку OSGi имеет сильную модульность, это работает не очень хорошо, требуя взломов, таких как Context Classloader, и других подверженных ошибкам вещей, которые в конечном итоге обычно не работают. OSGi µservices были изобретены для решения этого типа задач модульно и гораздо более элегантно.

Спецификация OSGi-JDBC (глава 125) определяет, как использовать JDBC в мире микросервисов: Пакет драйверов должен регистрировать org.osgi.service.jdbc.DataSourceFactory service. С помощью этой службы легко создать объединенный источник данных. По опыту я знаю, что база данных H2 делает это из коробки (спасибо, ребята, H2! Отличный продукт). К счастью, Ops4j имеет здесь проект, который предоставляет адаптер для MySql. Поскольку MySql не является стандартным и доступен в виде пакета OSGi, вы можете посмотреть здесь

Итак, после установки драйвера 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 из вашего кода, синглтонов, статики (глобальные переменные) и загрузки динамических классов. Конечно, если вы генерируете SQL, который зависит от MySQL, вы можете сделать это явным. Вы можете использовать @Reference так:

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

Или, лучше, вы разрешите разработчику вашего приложения установить это с помощью Configuration Admin. Просто установите для свойства DataSourceFactory.target значение «(osgi.jdbc.driver.name = mysql)», это позволит вам динамически подключать сервисы.

person Peter Kriens    schedule 29.07.2013
comment
Не могли бы вы взглянуть на мой вопрос, пожалуйста, stackoverflow.com/questions/42566102/ - person Marc; 03.03.2017