Должны ли результирующие наборы и операторы JDBC закрываться отдельно, хотя соединение закрывается после этого?

считается хорошей привычкой закрывать все ресурсы JDBC после использования. Но если у меня есть следующий код, необходимо ли закрывать Resultset и оператор?

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {};
    try { if (stmt != null) stmt.close(); } catch (Exception e) {};
    try { if (conn != null) conn.close(); } catch (Exception e) {};
}

вопрос в том, выполняет ли закрытие соединения эту работу или оставляет некоторые ресурсы в использовании.

8 ответов


что вы сделали идеально и очень хорошая практика.

причина, по которой я говорю свою хорошую практику... Например, если по какой-то причине вы используете "примитивный" тип пула баз данных и вызываете connection.close(), соединение будет возвращено в пул и ResultSet/Statement никогда не будет закрыт, а затем вы столкнетесь со многими новыми проблемами!

так что вы не всегда можете рассчитывать на connection.close() очистить.

надеюсь, это поможет:)


в Java 1.7 делает нашу жизнь намного проще благодаря оператор try-with-resources.

try (Connection connection = dataSource.getConnection();
    Statement statement = connection.createStatement()) {
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do stuff with the result set.
    }
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do more stuff with the second result set.
    }
}

этот синтаксис довольно краткий и элегантный. И connection действительно будет закрыт, даже если statement не удалось создать.


С javadocs:

когда


теперь я использую Oracle с Java. Вот моя точка зрения:--11-->

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

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

вот учебник закрыть ResultSet по завершении:

закрыть ResultSet по завершении

закрыть ResultSet объект, как только вы закончите работа с ResultSet объект даже хотя


Если вы хотите получить более компактный код, я предлагаю использовать Apache Commons DbUtils. В этом случае:

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(stmt);
    DbUtils.closeQuietly(conn);
}

правильный и безопасный метод для закрытия ресурсов, связанных с JDBC this (взято из Как правильно закрыть ресурсы JDBC-каждый раз):

Connection connection = dataSource.getConnection();
try {
    Statement statement = connection.createStatement();

    try {
        ResultSet resultSet = statement.executeQuery("some query");

        try {
            // Do stuff with the result set.
        } finally {
            resultSet.close();
        }
    } finally {
        statement.close();
    }
} finally {
    connection.close();
}

с формой Java 6 я думаю, что лучше проверить, что она закрыта или нет до закрытия (например, если какой - то пул соединений выселяет соединение в другом потоке) - например, какая-то сетевая проблема-оператор и состояние resultset могут быть закрыты. (это не часто случается, но у меня была эта проблема с Oracle и DBCP). Мой шаблон для этого (в более старом синтаксисе Java):

    try {
        ...   
        return resp;
    } finally {
        if (rs != null && !rs.isClosed()) {
            try {
                rs.close();
            } catch (Exception e2) { 
                log.warn("Cannot close resultset: " + e2.getMessage());
           }
        }
        if (stmt != null && !stmt.isClosed()) {
            try {
               stmt.close();
            } catch (Exception e2) {
                log.warn("Cannot close statement " + e2.getMessage()); 
            }
        }
        if (con != null && !conn.isClosed()) {
            try {
                con.close();
            } catch (Exception e2) {
                log.warn("Cannot close connection: " + e2.getMessage());
            }
    }

теоретически это не 100% идеально, потому что между проверкой состояния закрытия и закройте себя есть немного места для изменения состояния. В худшем случае вы получите предупреждение в лонг. - но это меньше, чем возможность изменения состояния в долгосрочных запросах. Мы используем этот шаблон в производстве с загрузкой "avarage" (150 одновременных пользователей), и у нас не было проблем с ним - поэтому никогда не видите это предупреждающее сообщение.


нет, вам не нужно ничего закрывать, кроме соединения. В спецификации JDBC для закрытия выше объект автоматически закрылись выше объекты. Закрытие Connection закрытие Statements, которое создало соединение. Закрытие любого Statement закрыть все ResultSets, которые были созданы этим Statement. Не имеет значения, если Connection является объединяемым или нет. Даже poolable соединение должно очистить перед возвращением в бассейн.

конечно, у вас могут быть длинные вложенные циклы на Connection создание множества операторов, а затем их закрытие подходит. Я почти никогда не закрыть!--3--> хотя, кажется чрезмерным при закрытии Statement или Connection закроет их.