Драйвер PostgreSQL JDBC logUnclosedConnections не работает

#java #postgresql #jdbc

Вопрос:

Я тестирую дополнительные свойства драйвера JDBC PostgreSQL, чтобы проверить, может ли он помочь обнаружить утечки соединения. Несмотря на то, что я намеренно не закрыл соединение, подготовленное заявление, набор результатов, об ошибках не сообщается.

Как я могу заставить logUnclosedConnections себя работать.

Вот мой пример программы

 public static void main( String[] args ) throws Exception {

    Properties dbProps = new Properties();
    dbProps.setProperty( "user", "xxxxxxx" );
    dbProps.setProperty( "password", "xxxxxxxxxx" );
    dbProps.setProperty( "logServerErrorDetail", "true" );
    dbProps.setProperty( "logUnclosedConnections", "true" );
    dbProps.setProperty( "loggerLevel", "DEBUG" );

    Connection conn = DriverManager.getConnection( "jdbc:postgresql://xxxxx.xxxxx.xxx:xxx/xxxxx", dbProps );

    try {
        PreparedStatement pstmt = conn.prepareStatement( "select count(*) from xx.xx limit 10" );

        ResultSet rSet = pstmt.executeQuery();

        while ( rSet.next() ) {
            System.out.println( "count is "   rSet.getInt( 1 ) );

        }

    } catch ( Exception e ) {

        e.printStackTrace();
    }
}
 

В результате получается

 count is 687
Sep 08, 2021 12:21:44 PM org.postgresql.Driver connect
FINE: Connecting with URL: jdbc:postgresql://xxxxx.xxxx.xxxx:xxx/xxxx
Sep 08, 2021 12:21:44 PM org.postgresql.jdbc.PgConnection <init>
FINE: PostgreSQL JDBC Driver 42.2.23
Sep 08, 2021 12:21:44 PM org.postgresql.jdbc.PgConnection setDefaultFetchSize
FINE:   setDefaultFetchSize = 0
Sep 08, 2021 12:21:44 PM org.postgresql.jdbc.PgConnection setPrepareThreshold
FINE:   setPrepareThreshold = 5
Sep 08, 2021 12:21:44 PM org.postgresql.core.v3.ConnectionFactoryImpl openConnectionImpl
FINE: Trying to establish a protocol version 3 connection to xxxx.xxxx.xxx:xxx
Sep 08, 2021 12:21:44 PM org.postgresql.core.v3.ConnectionFactoryImpl tryConnect
FINE: Receive Buffer Size is 65,536
Sep 08, 2021 12:21:44 PM org.postgresql.core.v3.ConnectionFactoryImpl tryConnect
FINE: Send Buffer Size is 65,536
Sep 08, 2021 12:21:44 PM org.postgresql.ssl.MakeSSL convert
FINE: converting regular socket connection to ssl
 

Изменить 1

Изменения, предложенные @Scary Wombat и @Stephen C, но результат тот же.

Никаких сообщений о незамкнутом соединении.

 public static void main( String[] args ) throws Exception {

    Properties dbProps = new Properties();
    dbProps.setProperty( "user", "postgres" );
    dbProps.setProperty( "password", "AuR0ra$dba#$" );
    dbProps.setProperty( "logServerErrorDetail", "true" );
    dbProps.setProperty( "logUnclosedConnections", "true" );
    dbProps.setProperty( "loggerLevel", "DEBUG" );

    Connection conn = DriverManager.getConnection( "jdbc:postgresql://devdbmaster.koncert.com:5499/dev_koncert_v10.5", dbProps );

    try {

        for ( int i = 0; i < 100; i   ) {
            PreparedStatement pstmt = conn.prepareStatement( "select count(*) from cl.users limit 10" );

            ResultSet rSet = pstmt.executeQuery();

            while ( rSet.next() ) {
                System.out.println( "count is "   rSet.getInt( 1 ) );

            }

            Thread.sleep( 10 );
        }

    } catch ( Exception e ) {

        e.printStackTrace();
    }
    conn = null;
    System.gc();
    Thread.sleep( 1 );
}
 

Правка 2

добавлено conn = null; ранее System.gc(); , как было предложено @Gus и @Stephen C

Комментарии:

1. В конечном итоге эти объекты будут собраны в мусор, и будет вызван метод finalize (), который закроет соединение, если вызывающий абонент не сделал этого сам. Я предполагаю, что в этом упрощенном коде не происходит GC.

2. @ScaryWombat Любые мысли о том, как это сделать

3. Повторите несколько сотен раз, возможно, немного поспав.

4. Я думаю, что здесь происходит то, что вся виртуальная машина разрушается до того, как необходимо запустить отдельные завершители. Обратите внимание, что вы вызываете System.gc() , когда соединение все еще находится в области действия и назначено переменной conn . Таким образом, его невозможно собрать-он все еще используется в JVM и, конечно, не недоступен. Возможно, было бы достаточно просто установить conn значение null перед вызовом gc.

5. @Гас попробовал, как и предлагалось, но результат тот же

Ответ №1:

В соответствии с документацией драйвера JDBC PostgreSQL:

logUnclosedConnections = boolean

Клиенты могут пропустить Connection объекты, не вызвав его close() метод. В конечном итоге эти объекты будут собраны в мусор, и finalize() будет вызван метод, который закроет Connection вызывающий объект, если он не сделал этого сам. Использование финализатора-это всего лишь временное решение.

Чтобы помочь разработчикам обнаружить и исправить источник этих утечек logUnclosedConnections , был добавлен параметр URL. Он фиксирует трассировку стека при каждом Connection открытии, и если finalize() метод достигнут без закрытия, трассировка стека выводится в журнал.

Итак, то, что вы здесь тестируете, — это механизм, предназначенный для отладки неисправного кода, который приводит к утечке Connection объектов.

Проблема в том, что вы неправильно его тестируете. Как указано в описании, механизм зависит от того, находит ли сборщик мусора недостижимые Connection объекты. Чтобы это сработало, должны произойти 3 вещи:

  1. GC нужно запустить.
  2. ГК нужно найти недостижимое Connection . Обратите внимание, что GC не гарантирует, что при каждом запуске он будет находить все недостижимые объекты.
  3. После запуска GC Connection необходимо завершить работу с найденными недостижимыми объектами.

Это ваш тест, вы создаете и используете a Connection , а затем main завершаете, завершая JVM. К моменту main окончания GC не запустилась. Таким образом, утечка Connection не обнаружена.

Чтобы этот тест «работал», вам нужно добавить следующее в конце тела цикла;

   rRet = null;
  pstmt = null;
 

Затем добавьте в конце main метода:

   conn = null;
  System.gc();
  Thread.sleep(1);
 

Нулевые назначения делают Connection их недоступными. (Обратите внимание, что PreparedStatement и ResultSet будет относиться к Connection . Нам нужно уничтожить все ссылки, которые могли бы сделать Connection это доступным.)

В System.gc() заявлении содержится просьба к JVM запустить GC.

Thread.sleep(1) Заявление ждет еще секунду … таким образом, JVM получает возможность запустить завершитель соединения до завершения JVM.


Я говорю «работать» в кавычках по нескольким причинам:

  1. Вы не должны делать такого рода вещи в производственном коде. Звонить System.gc() неэффективно. Лучшая идея-просто позволить GC работать, когда JVM сочтет это необходимым.
  2. На самом деле, System.gc() не гарантируется вообще ничего делать. Аналогичным образом, вы не можете полагаться на то, что завершители будут запущены немедленно. Таким образом, существуют сценарии, в которых два добавленных оператора не будут работать.

Комментарии:

1. Спасибо за ответ @Stephen C. Как вы и предлагали, попробовал внести изменения, но результат тот же. Нет отчета о незамкнутых соединениях.

2. Ах … да. Установите conn значение null перед вызовом System.gc() . conn Переменная, скорее всего, все еще будет доступна … до main выхода.

3. conn = null; System.gc(); все то же

4. Назначьте null pstmt и rSet также. У них будут ссылки на объект подключения.

5. Обратите внимание, что я не тестирую это, потому что не хочу устанавливать PostgreSQL на свою машину …