Spring ORM с C3P0 или DBCP пропускает соединения - PullRequest
4 голосов
/ 19 октября 2011

В последних версиях DBCP и C3P0, использующих поддержку Spring Ibatis, я сталкиваюсь с проблемой утечки соединений.

Сценарий состоит в том, что в журнале работает SQL, который блокирует несколько таблиц. Это приводит к тому, что количество подключений в моем пуле становится максимальным, поскольку пользователи запускают запросы, которые попадают в заблокированные таблицы. Наконец, администратор заходит в MySQL и делает kill query <id> на долгосрочном SQL.

Если имеется достаточно потоков (в моем случае около 50 или более), ожидающих возврата потока БД в пул, то я вижу что-то вроде следующего в дампе потока:

 java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1315)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
    - locked <0x00002aaacbb01118> (a com.mchange.v2.resourcepool.BasicResourcePool)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:113)
    at 

или

  java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1104)
    - locked <0x00002aab0f030620> (a org.apache.commons.pool.impl.GenericObjectPool$Latch)
    at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:113)
    at 

и эти темы ждут ВСЕГДА.

Этого не происходит, если пул исчерпан, и только несколько (около 5) потоков ожидают свободного соединения в пуле.

Я знаю, что есть конфигурация, которая может решить эту проблему (установка времени ожидания и т. Д.), Но меня интересует, почему это происходит в первую очередь? Почему активные потоки не возвращаются в пул, когда существует 50 или более потоков, ожидающих соединения, и я уничтожаю долго работающий SQL?

Обновление: Я должен был дать понять, что использую Spring 3.0.2 и Ибатис 2.3. Я использую SqlMapClientTemplate, который управляет моим связи для меня. На данный момент, я начинаю думать, что это Ibatis 2.3 не справляется с тяжелыми грузами правильно.

Ответы [ 3 ]

5 голосов
/ 24 октября 2011

При использовании c3po я настоятельно рекомендую попробовать эту функцию . Утечки соединения обычно появляются, когда вы выполняете изменения базы данных вне транзакции. Соединение с незафиксированными записями не может быть повторно использовано и потеряно из пула. Если вы включите эту отладку с достаточно длительным таймаутом, вы сможете увидеть следы стека с подозрительными операциями с базой данных.

Убедитесь, что операции, видимые в трассировках стека, правильно управляют транзакциями. Также следите за использованием пула соединений, установив в логгерах c3p0 уровень отладки.

2 голосов
/ 19 октября 2011

Просто добавьте к комментарию @ BalusC и @ ответ JoshDM , когда вы вызываете close() на Connection в своем Java-коде, за кулисами это фактически просто проверяет это соединение обратно впул соединений, а не физически закрывать его.Вот почему важно всегда закрывать соединения через ваш Java-код, независимо от того, объединяет ли их базовый драйвер JDBC.

Подробнее об этом на в этом посте .

2 голосов
/ 19 октября 2011

Очень похоже на то, что @ BalusC спрашивает, вы закрываете свои соединения? Они должны быть закрыты в предложении finally вашего Java try-catch-finally. Оберните каждый connection.close() метод в свой try { con.close() } catch (Exception ignore) {}

По желанию вы должны сделать это для ResultSet, затем Statement, затем Connection в указанном порядке. Объявите ваши Connection, Statement и ResultSet вне вашего исходного блока try как null и создайте экземпляр в вашем блоке try.

Connection con = null;
Statement stmt = null;
ResultSet rs = null;

try {

    con = getConnectionFromPoolMethod();

    // ...
    // instantiate your statement and result set as normal
    // make your sql call; 
    // extract data from result set to appropriate POJO

} catch (Exception ex) {
    // handle your exception, log, wrap, enhance or rethrow or whatever
} finally {
    if (rs != null) try { rs.close(); } catch (Exception ignore) {}
    if (stmt != null) try { stmt.close(); } catch (Exception ignore) {}
    if (con != null) try { con.close(); } catch (Exception ignore) {}
}

Если вы настроены на это, а не на весь вышеуказанный код в каждом finally, который оборачивает вызов SQL, вы можете использовать DbUtils служебный класс Apache Commons DbUtils .

import org.apache.commons.dbutils.DbUtils;

и применить методы closeQuietly. Блок finally будет выглядеть следующим образом:

} finally {
    DbUtils.closeQuietly(con, stmt, rs);
}
...