Выпуск ресурсов JDBC - PullRequest
       11

Выпуск ресурсов JDBC

1 голос
/ 28 ноября 2011

В моем приложении произошла утечка памяти в результате использования JDBC.Я проверил это, посмотрев на визуальный дамп кучи и увидев тысячи экземпляров ResultSet и связанных объектов.Мой вопрос, таким образом, как мне правильно управлять ресурсами, используемыми JDBC, чтобы они могли собирать мусор?Нужно ли вызывать «.close ()» для каждого используемого оператора?Нужно ли вызывать «.close ()» для самих ResultSets?

Как бы вы освободили память, используемую при вызове:

ResultSet rs = connection.createStatement().executeQuery("some sql query");

??

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

:: EDIT :: Добавление некоторых примеров кода

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

Этот для выполнения операторов вставки или обновления:

public int executeCommand(String sqlCommand) throws SQLException {
    if (connection == null || connection.isClosed()) {
        sqlConnect();
    }
    Statement st = connection.createStatement();
    int ret = st.executeUpdate(sqlCommand);
    st.close();
    return ret;
}

И этоодин для возврата ResultSets из выбора:

public ResultSet executeSelect(String select) throws SQLException {
    if (connection == null || connection.isClosed()) {
        sqlConnect();
    }
    ResultSet rs = connection.createStatement().executeQuery(select);
    return rs;
}

После использования метода executeSelect () я всегда вызываю resultset.getStatement (). close ()

Examiningдамп кучи с отслеживанием выделения объектов в операторах show, которые все еще удерживаются обоими этими методами ...

Ответы [ 4 ]

2 голосов
/ 28 ноября 2011

Да, ResultSets и Statements всегда должны быть закрыты в блоке finally.Использование оболочек JDBC, таких как Spring JdbcTemplate, помогает сделать код менее подробным и закрыть все для вас.

2 голосов
/ 28 ноября 2011

Вам следует закрыть Заявление, если вы не собираетесь его повторно использовать. Обычно рекомендуется сначала закрыть ResultSet, так как некоторые реализации не закрывали ResultSet автоматически (даже если они должны были).

Если вы повторяете одни и те же запросы, вам, вероятно, следует использовать PreparedStatement, чтобы уменьшить накладные расходы при разборе. И если вы добавляете параметры в свой запрос, вам действительно следует использовать PreparedStatement, чтобы избежать риска внедрения SQL.

1 голос
/ 28 ноября 2011

Я скопировал это из проекта, над которым я работал. Я нахожусь в процессе рефакторинга, чтобы использовать Hibernate (из кода должно быть понятно почему !!). Использование инструмента ORM, такого как Hibernate, является одним из способов решения вашей проблемы. В противном случае, вот как я использовал обычные DAO для доступа к данным. В нашем коде нет утечки памяти, так что это может помочь в качестве шаблона. Надеюсь, это поможет, утечки памяти ужасны!

@Override
public List<CampaignsDTO> getCampaign(String key) {
    ResultSet resultSet = null;
    PreparedStatement statement = null;
    try {
        statement = connection.prepareStatement(getSQL("CampaignsDAOImpl.getPendingCampaigns"));
        statement.setString(1, key);
        resultSet = statement.executeQuery();

        List<CampaignsDTO> list = new ArrayList<CampaignsDTO>();

        while (resultSet.next()) {
            list.add(new CampaignsDTO(
                    resultSet.getTimestamp(resultSet.findColumn("cmp_name")), 
                    ...));
        }
        return list;
    } catch (SQLException e) {
        logger.fatal(LoggerCodes.DATABASE_ERROR, e);
        throw new RuntimeException(e);
    } finally {
        close(statement);
    }
} 

Метод close () выглядит следующим образом:

public void close(PreparedStatement statement) {
    try {
        if (statement != null && !statement.isClosed())
            statement.close();
    } catch (SQLException e) {
        logger.debug(LoggerCodes.TRACE, "Warning! PreparedStatement could not be closed.");
    }
}
0 голосов
/ 28 ноября 2011

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

Вы должны убедиться, что вы также закрыли все ресурсы JDBC в исключительных случаях.

Использовать блок Try-Catch-finally - например:

try {
    conn = dataSource.getConnection();
    stmt = conn.createStatement();
    rs = stmet.executeQuery("select * from sometable");
    stmt.close();
    conn.close();
} catch (Throwable t) {
    // do error handling
} finally {
    try {
         if (stmt != null) { 
             stmt.close();
         }
         if (conn != null) { 
             conn.close();
         }
    } catch(Exception e) {

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