Закриття підключень до бази даних на Java


121

Я трохи заплутався, читав нижче з http://en.wikipedia.org/wiki/Java_Database_Connectivity

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    //It's important to close the statement when you are done with it
    stmt.close();
}

Вам не потрібно закривати з'єднання Conn? Що насправді відбувається, якщо conn.close () не відбувається?

У мене є приватний веб-додаток, який я стверджую, що наразі не закриває жодної форми, але чи є важливим насправді той, чи один, stmt, conn або обидва?

Сайт постійно перебуває вниз, але сервер продовжує говорити, що це проблема з підключенням до бази даних, я підозрюю, що він не закритий, але я не знаю, що потрібно закрити.


Завжди найкраща практика закривати з'єднання самостійно, не залежно від інших драйверів та шаблонів для закриття. Якщо не закрити з'єднання, розетки та ресурси відкриються назавжди до збоїв (не більше сценарію ресурсів) або перезавантаження.
Арун Джошла

Відповіді:


196

Коли ви закінчите з використанням свого Connection, вам потрібно явно закрити його, зателефонувавши до його close()методу, щоб звільнити будь-які інші ресурси бази даних (курсори, ручки та ін.), До яких може утримуватися з'єднання.

Насправді, безпечний зразок в Java полягає в тому, щоб закрити свої ResultSet, Statementі Connection(в такому порядку) в finallyблоці, коли ви закінчите з ними, щось подібне:

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* ignored */}
    }
}

finallyБлок може бути трохи поліпшений в (щоб уникнути перевірок нуля):

} finally {
    try { rs.close(); } catch (Exception e) { /* ignored */ }
    try { ps.close(); } catch (Exception e) { /* ignored */ }
    try { conn.close(); } catch (Exception e) { /* ignored */ }
}

Але все-таки це надзвичайно багатослівно, тому ви, як правило, використовуєте хелперний клас, щоб закрити об'єкти в безпечних допоміжних методах і finallyблок стає чимось таким:

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

Насправді, у DbUtils Apache Commons є DbUtilsклас, який саме це робить, тому немає потреби писати свій власний.


3
Чудова допомога, дякую! Я не спіймав і не думав про conn! = Нульові твердження.
onaclov2000

1
@ Onaclov2000 Так rs, ps, connможе бути в nullзалежності від того, де розриви коду. Ось чому це відоме як «безпечний» зразок.
Паскаль Thivent

12
@Pascal Thivent: Насправді нам не потрібно закривати їх усіх. У книзі "Основний Java-том другого - додаткові функції" написано: closeМетод Statementоб'єкта автоматично закриває асоційований, ResultSetякщо в операторі є відкритий набір результатів. Аналогічним чином , closeметод Connectionкласу закриває все Statementsз Connection.
Маджід Азімі

12
@Majid: Якщо це не з'єднання. Тоді твердження просочуються.
BalusC

1
@BalusC: Чи можете ви, будь ласка, пояснити, що відбувається, коли об'єднане з'єднання закрите, використовуючи метод connection.close ()
Krsna Chaitanya

61

Завжди краще закрити об’єкти бази даних / ресурсів після використання. Краще закрити з'єднання, набір результатів та об’єкти операторів у finallyблоці.

До Java7 всі ці ресурси потрібно закрити за допомогою finallyблоку. Якщо ви використовуєте Java 7, то для закриття ресурсів ви можете зробити наступне.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

//statements
}catch(....){}

Тепер об'єкти con, stmt та rs стають частиною пробного блоку, і java автоматично закриває ці ресурси після використання.

Сподіваюся, я був корисним.


Що робити, якщо моє твердження неявне, тобто ResultSet rs = conn.createStatement().executeQuery(sql);всередині tryблоку?
Antares42

1
Ви не зможете посилатися на них у остаточному {} блоці для закриття. Якщо викинутий виняток, метод закриття () ResultSet ніколи не буде застосовано
Dan

Що станеться, якщо я їх не закрию?
Alex78191

якщо ви не закриваєте їх, то може статися витік пам'яті.
Яду Крішнан

14

Досить просто закрити Statementі Connection. Немає необхідності явно закривати ResultSetоб’єкт.

Документація Java говорить про java.sql.ResultSet:

Об'єкт ResultSet автоматично закривається об'єктом Statement, який його генерував, коли цей об'єкт Заяви закритий, повторно виконаний або використовується для отримання наступного результату з послідовності декількох результатів.


Дякую BalusC за коментарі: "Я б на це не покладався. Деякі драйвери JDBC не в цьому".


25
Я б на це не покладався. Деякі драйвери JDBC не вдається. Наприклад, Oracle з "Максимально відкриті курсори перевищені" тощо. Просто явно закрийте всі відкриті ресурси, ніяких виправдань.
BalusC

1
Я б швидше не користувався драйверами, які не відповідають вимогам, а потім
Enerccio

2
Як зазначає BalusC, добре захисним програмуванням явно закрити з'єднання, а не з'єднати залежність від конкретного постачальника.
michaelok

11

Так. Вам потрібно закрити набір результатів, оператор та з'єднання. Якщо з'єднання відбулося з пулу, закриття його фактично надсилає назад до пулу для повторного використання.

Зазвичай це потрібно робити в finally{}блоці, так що якщо виняток буде викинуто, ви все одно отримаєте шанс закрити це.

Багато систем вирішать проблему розподілу / розсилки ресурсів для вас. наприклад JdbcTemplate Spring . Apache DbUtils має методи перевірки закриття набору результатів / оператора / з'єднання нульовим чи ні (та вилучення винятків після закриття), що також може допомогти.


1
Коли я вставляю "нарешті" затемнення подобається виділяти його, кажучи мені, що це неправильно. це повинно йти після блоків вилову?
onaclov2000

Так. спробуйте {} зловити {} нарешті {}. Улов {} необов’язковий, btw. Так само, як і нарешті {}
Брайан Агнеу

Я перенесла "тісні" заяви нарешті, але вони просто говорять "sqlexception", якісь пропозиції?
onaclov2000

1
close () кидає SQLException. Ви повинні з цим впоратися. Див. DbUtils.closeQuietly (), щоб це мовчки поводитися.
Брайан Агнеу

> Що насправді відбувається, якщо conn.close () не відбувається?
Alex78191

8

Насправді, найкраще, якщо ви використовуєте блок "пробний ресурс", і Java закриє всі з'єднання для вас, коли ви виходите з блоку спробу.

Ви повинні зробити це з будь-яким об'єктом, який реалізує функцію автоматичного закриття.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

Заклик до getDatabaseConnection лише складений. Замініть його на виклик, який отримує з'єднання JDBC SQL або з'єднання з пулу.


Тож вам не доведеться вручну закривати з'єднання в цьому випадку?
Колін Д

1
Правильно. Не потрібно явно закривати з'єднання. Він буде закритий, коли буде досягнуто завершення блоку спробу коду.
Джо

7

Так, вам потрібно закрити З'єднання. В іншому випадку клієнт бази даних, як правило, буде тримати відкрите з'єднання сокета та інші ресурси.


... поки не вийде. Це пов'язує різні обмежені ресурси на стороні клієнта та сервера. Якщо клієнт робить подібні речі занадто багато, це може спричинити проблеми для самого клієнта, служби бази даних і, можливо, навіть для інших програм, що працюють на клієнтській або серверній машині.
Стівен С
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.