HikariCP обнаруживает утечку соединения, даже если во всем моем коде есть вызов метода close

#java #vaadin #hikaricp

#java #vaadin #hikaricp

Вопрос:

Я использую HikariCP в нашем веб-приложении, и внезапно я получаю это исключение:

     [Hikari housekeeper (pool HikariPool-0)] WARN com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for connection com.mysql.cj.jdbc.ConnectionImpl@3b82d04f, stack trace follows
  

java.lang.Исключение: обнаружена явная утечка соединения

Я уже проверил и убедился, что во всех моих sql-кодах есть вызов метода close .

Вот мой HikariConfig :

     private HikariConfig hikariConfig() {
    HikariConfig config = new HikariConfig();
    config.setDriverClassName(CLASS_FOR_NAME);
    config.setJdbcUrl(HOST);
    config.setUsername(USER);
    config.setPassword(PASS);
    config.addDataSourceProperty("cachePrepStmts", "true");
    config.addDataSourceProperty("prepStmtCacheSize", "250");
    config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    config.setLeakDetectionThreshold(TimeUnit.SECONDS.toMillis(30));
    config.setValidationTimeout(TimeUnit.MINUTES.toMillis(1));
    config.setMaximumPoolSize(40);
    config.setMinimumIdle(0);
    config.setMaxLifetime(TimeUnit.MINUTES.toMillis(2)); // 120 seconds max life time
    config.setIdleTimeout(TimeUnit.MINUTES.toMillis(1)); // minutes
    config.setConnectionTimeout(TimeUnit.MINUTES.toMillis(5)); // millis
    config.setConnectionTestQuery("/* ping */ SELECT 1");

    return config;
}
  

вот как выглядят мои запросы :

    public ArrayList<LocationType> getLocationTypes() {
    ArrayList<LocationType> locationTypes = new ArrayList<>();
    Connection connection = null;
    PreparedStatement pstmt = null;
    ResultSet resultSet = null;

    try {
        connection = DataSource.getInstance().getConnection();

        pstmt = connection.prepareStatement("SELECTn"  
                "  location_type_id,n"  
                "  location_type_namen"  
                "FROM tablename;");

        resultSet = pstmt.executeQuery();

        while (resultSet.next()) {
            locationTypes.add(new LocationType(resultSet.getInt("location_type_id"), resultSet.getString("location_type_name")));
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (resultSet != null)
            try {
                resultSet.close();
            } catch (SQLException e) {
            }

        if (pstmt != null)
            try {
                pstmt.close();
            } catch (SQLException e) {
            }

        if (connection != null)
            try {
                connection.close();
            } catch (SQLException e) {
            }
    }
    return locationTypes;
}
  

Я уже пробовал увеличить обнаружение утечки соединения, максимальное соединение и минимальное время ожидания, но ничего из этого не решило проблему.

Я читал, что это может быть вызвано тем, что машина (низкие ресурсы) и соединения закрыты, я думаю, однако, ни одно из них не вызывает проблемы.

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

Это трассировка стека :

     at com..database.DataSource.getConnection(DataSource.java:148)
at com.database.databaseServices.MileageReportService.MileageService.getMonthlySummaryBySID(MileageService.java:27)
at com.views.reports.mileage.MileageReport.lambda$generateReport$61446b05$1(MileageReport.java:103)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
  

Единственная строка в этой строке — MileageService.java:27 — это мой запрос к БД, и в его вызове finally есть оператор close .

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

1. какую версию Hikari CP вы используете?

2. также не могли бы вы поделиться трассировкой стека, которая следует за опубликованной вами строкой журнала?

3. Я использовал 2.4.3. Я только что обновил сегодня до 2.5.1, но я все еще получаю то же исключение.

4. Я добавил трассировку стека в свой вопрос @Ivan

5. @JRojo ты знаешь, сколько времени MileageService. getMonthlySummaryBySID ? Этот метод, похоже, является виновником, а не getLocationTypes .

Ответ №1:

Обновите до последней версии HikariCP.

HikariCP сообщает о соединении как об утечке, потому что время, затраченное на заимствование до закрытия, превышает указанный порог обнаружения утечки.

Версия 2.4.9 и более поздние версии регистрируются, если соединение возвращается после сообщения об утечке.

Кроме того, глядя на вашу конфигурацию, я бы изменил свойства следующим образом (от первых 4 до 1 минуты и до последних 5):

 config.setLeakDetectionThreshold(TimeUnit.MINUTES.toMillis(1));
config.setConnectionTimeout(TimeUnit.MINUTES.toMillis(1));
config.setValidationTimeout(TimeUnit.MINUTES.toMillis(1));
config.setIdleTimeout(TimeUnit.MINUTES.toMillis(1));

config.setMaxLifetime(TimeUnit.MINUTES.toMillis(5));
  

HTH

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

1. Привет, Нитин, спасибо за твой ответ. Я обновил свой hikariconfig тем, который вы предложили, но исключение все равно возникает. В настоящее время я использую hikari 2.5.1.

2. подождав пару минут, например, 5 или около того, я увидел журналы, в которых сообщалось, что соединение вернулось в пул. Несмотря на то, что время выполнения моего запроса не занимает и секунды, я не уверен, почему это занимает некоторое время после его реализации в моем Java-коде.

3. в журнале также отображается идентификатор соединения. вероятно, поместите инструкции отладки вокруг запроса, который, по вашему мнению, занимает секунду, а не 5 минут.