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(), есть причина его вызвать, и игнорировать его делается по вашей собственной опасности.