ResultSet не закрыт при закрытии соединения?

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

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

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

finally{
    try{
        rs.close()
    }catch(SqlException se){
        //log it
    }
    try{
        stmt.close();
    }catch(SqlException se){
        //log it
    }
    conn.close();
}

Но я столкнулся с вышеупомянутым шаблоном во многих проектах (из нескольких компаний), и никто не закрывал ResultSets или Statementments.

У вас были проблемы с ResultSets и заявлениями, которые не закрываются, когда соединение закрыто?

Я нашел только это, и это относится к Oracle, имеющему проблемы с закрытием ResultSets при закрытии Connections (мы используем Oracle db, следовательно, мои исправления). java.sql.api ничего не говорит в Connection.close() javadoc.

Ответ 1

Одна проблема с ТОЛЬКО закрытием соединения, а не с результирующим набором, заключается в том, что если ваш код управления соединением использует пул соединений, connection.close() просто вернет соединение обратно в пул. Кроме того, в некоторой базе данных есть ресурс курсора на сервере, который не будет освобожден должным образом, если он явно не закрыт.

Ответ 2

У меня были проблемы с незакрытыми ResultSets в Oracle, хотя соединение было закрыто. Ошибка, которую я получил, была

"ORA-01000: maximum open cursors exceeded"

Итак: всегда закрывайте ResultSet!

Ответ 3

Вы должны всегда закрывать все ресурсы JDBC явно. Как уже говорили Аарон и Джон, закрытие соединения часто возвращает его только в пул, и не все драйверы JDBC реализованы точно так же.

Вот полезный метод, который можно использовать из блока finally:

public static void closeEverything(ResultSet rs, Statement stmt,
        Connection con) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
}

Ответ 4

В этом случае Oracle даст вам ошибки об открытых курсорах.

В соответствии с: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

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

Все эти данные передаются поставщику драйверов JDBC.

Его всегда безопаснее закрывать все явно. Мы написали класс util, который обертывает все с помощью try {xxx} catch (Throwable {}, чтобы вы могли просто вызвать Utils.close(rs) и Utils.close(stmt) и т.д., Не беспокоясь об исключениях, которые закрывают сканирование, предположительно,.

Ответ 5

Мост ODBC может вызвать утечку памяти с некоторыми драйверами ODBC.

Если вы используете хороший драйвер JDBC, у вас не должно возникнуть никаких проблем с закрытием соединения. Но есть 2 проблемы:

  • Знаете ли вы, есть ли у вас хороший драйвер?
  • В будущем вы будете использовать другие драйверы JDBC?

Что лучше всего закрыть все это.

Ответ 6

Я работаю в большой веб-среде J2EE. У нас есть несколько баз данных, к которым можно подключиться по одному запросу. Мы начали получать логические блокировки в некоторых наших приложениях. Проблема заключалась в следующем:

  • Пользователь запрашивает страницу
  • Сервер подключается к DB 1
  • Выбор сервера в DB 1
  • Сервер "закрывает" подключение к DB 1
  • Сервер подключается к DB 2
  • в тупике!

Это произошло по двум причинам: мы столкнулись с гораздо большим объемом трафика, чем обычно, и J2EE Spec по умолчанию фактически не закрывает ваше соединение, пока поток не завершит выполнение. Итак, в приведенном выше примере шаг 4 никогда фактически не закрывал соединение, хотя в конечном итоге они были закрыты должным образом.

Чтобы исправить это, вам нужно использовать ссылки ресурсов в web.xml для ваших подключений к базе данных, и вам нужно установить область разделения репликации на нечеткую.

Пример:

<resource-ref>
    <description>My Database</description>
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>

Ответ 7

Я определенно видел проблемы с незакрытыми ResultSets, и что может помешать закрывать их все время, не так ли? Ненадежность необходимости запоминать это - одна из лучших причин для перехода к фреймворкам, которые управляют этими деталями для вас. Это может быть нецелесообразно в вашей среде разработки, но мне повезло с помощью Spring для управления транзакциями JPA. Беспорядочные детали открытия соединений, операторов, наборов результатов и написания чрезмерно сложных блоков try/catch/finally (с блоками try/catch в блоке finally!), Чтобы закрыть их снова, просто исчезают, оставляя вас на самом деле выполнять определенную работу, Я настоятельно рекомендую перейти на такое решение.

Ответ 8

В Java, выражения (not Resultsets) коррелируют с курсорами в Oracle. Лучше всего закрыть ресурсы, которые вы открываете, поскольку может произойти непредвиденное поведение в отношении JVM и системных ресурсов.

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

В общем случае, если на объекте существует метод close() или destroy(), есть причина его вызвать, и игнорировать его делается по вашей собственной опасности.