Закрытие соединений с базой данных в Java - PullRequest
106 голосов
/ 09 февраля 2010

Я немного запутался, я читал ниже от 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.close () не происходит?

У меня есть частное веб-приложение, которое я поддерживаю, которое в настоящее время не закрывает ни одну из форм, но действительно ли это действительно важная, стандартная или обе?

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

Ответы [ 6 ]

178 голосов
/ 09 февраля 2010

Когда вы закончите использовать 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);
}

И, собственно, Apache Commons DbUtils имеет класс DbUtils, который точно делает это, поэтому нет необходимости писать свой собственный.

55 голосов
/ 02 мая 2013

Всегда лучше закрыть объекты базы данных / ресурса после использования. Лучше закрыть объекты соединений, результатов и операторов в блоке 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 становятся частью блока try, и java автоматически закрывает эти ресурсы после использования.

Надеюсь, я был полезен.

13 голосов
/ 06 января 2013

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

В документации Java говорится о java.sql.ResultSet:

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


Спасибо BalusC за комментарии: "Я бы не стал полагаться на это. Некоторые драйверы JDBC отказывают в этом."

11 голосов
/ 09 февраля 2010

Да. Вам необходимо закрыть набор результатов, оператор и соединение. Если соединение пришло из пула, его закрытие фактически отправляет его в пул для повторного использования.

Обычно вы должны сделать это в блоке finally{}, чтобы в случае возникновения исключения вы все равно имели возможность закрыть это.

Многие фреймворки позаботятся об этой проблеме выделения / освобождения ресурсов. например Spring's JdbcTemplate . Apache DbUtils имеет методы для поиска после закрытия результирующего набора / оператора / соединения, равного нулю или нет (и перехват исключений при закрытии), что также может помочь.

7 голосов
/ 09 февраля 2010

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

4 голосов
/ 13 сентября 2017

На самом деле, лучше всего, если вы используете блок try-with-resources и Java закроет все соединения для вас, когда вы выйдете из блока try.

Вы должны сделать это с любым объектом, который реализует AutoClosable.

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 или соединение из пула.

...