Java, ResultSet.close (), PreparedStatement.close () - зачем? - PullRequest
7 голосов
/ 02 февраля 2011

В своем веб-приложении я широко использую базу данных.

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

Мой вопрос: что хуже всего может случиться, если я никогда не закрою ResultSet s, PreparedStatement s и Statement s, которые создают мои наследующие сервлеты, если Connection sчто их создавать всегда закрыто?

Ответы [ 5 ]

9 голосов
/ 02 февраля 2011

Javadoc для Оператор # close () говорит:

Примечание. Когда объект Statement закрывается, его текущий объект ResultSet, если таковой существует, также закрывается.

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

Javadoc для Connection # close () не дает соответствующей гарантии, но говорит:

Освобождает базу данных этого объекта Connection и ресурсы JDBC немедленно, вместо того, чтобы ожидать их автоматического освобождения.

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

5 голосов
/ 02 февраля 2011

Я почти уверен, что закрытие соединения закроет связанные выражения, ResultSets и другие связанные объекты.Однако все это потребляет ресурсы как на клиенте, так и на сервере базы данных, пока соединение не будет закрыто.

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

Однако это справедливо только в текущих настройках. Если Когда ваше приложение изменится, вы можете столкнуться с проблемами из-за того, что вы не закрыли свои выписки и наборы результатов.

Хотя вы не хотите использовать пул соединений, я думаю, что это плохая идеядаже с небольшим количеством пользователей / операций, поскольку открытие соединения с базой данных не дешево.Таким образом, даже в вашем контексте пул соединений может помочь сделать вашу систему более отзывчивой.

Просто заметка о сборке мусора.Перед закрытием соединения неиспользуемые выписки или наборы результатов могут быть GCed. Но когда дело доходит до освобождения системных ресурсов, таких как файлы или, в более общем случае, не-Java-ресурсов (таких как курсоры на сервере базы данных), на GV JVM не следует полагаться.Например, если ваше клиентское приложение открывает много ResultSets, но использует только небольшую часть выделенной памяти кучи, GC никогда не включится, пока сервер базы данных задохнется от открытых курсоров.

1 голос
/ 05 ноября 2014

Это немного дерьмо Api - в конечном итоге вы пишете код котельной плиты.

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

Пока у вас есть IDE, которая может генерировать делегирующие вам методы в классе, это тривиальная задача для переносаи тому подобное.

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

Я создал небольшой класс для отслеживания различных вещей:

public class CleanupList
{
    private final ArrayList<AutoCloseable> _disposables;

    public CleanupList()
    {
        _disposables = new ArrayList<>();
    }

    public void cleanup()
    {
        for(AutoCloseable closeable : _disposables){
            //it sucks that they put an exception on this interface
            //if anyone actually throws an exception in a close method then there's something seriously wrong going on
            //they should have copied the c# more closely imo as it has nicer syntax aswell
            try
            {
                closeable.close();
            }
            catch (Exception e)
            {
                throw new RuntimeException(e);
            }
        }

        _disposables.clear();
    }

    public <T extends AutoCloseable> T track(T statement)
    {
        _disposables.add(statement);
        return statement;
    }
}

А затем, например, в Wrapped Connection (что-токоторый оборачивает соединение с базой данных):

public class WrappedConnection implements AutoCloseable
{
    private final CleanupList _cleanupList;
    private Connection _connection;

    public WrappedConnection(Connection connection)
    {
        _connection = connection;
        _cleanupList = new CleanupList();
    }

    public void close()
    {
        try
        {
            _connection.close();
            _cleanupList.cleanup();
        }
        catch (SQLException e)
        {
            throw new RuntimeException(e);
        }
    }

    public PreparedStatement prepareStatement(String sql)
    {
        try
        {
            return trackForDisposal(_connection.prepareStatement(sql));
        } 
        catch (SQLException e)
        {
            throw new RuntimeException(e);
        }
    }

    private <T extends AutoCloseable> T trackForDisposal(T statement)
    {
        return _cleanupList.track(statement);
    }

.... lots more methods
}

Затем вы можете также передать тот же список в упакованные версии PreparedStatement/ Наборы результатов (которые я здесь не показывал) и т. Д. И используют их аналогичным образом.

Я не знаю, что используют другие люди, но в IDEA вы можете включить предупреждение для автоматического закрытиявещи, которые не находятся в блоке использования (или я должен сказать, попытка с ресурсами):

try(SomethingThatNeedsClosing somethingThatNeedsClosing = new SomethingThatNeedsClosing()){
    //do stuff
}

Эти блоки использования позволяют вам окончательно автоматически закрываться и могут использоваться только с объектами AutoClosable.тип интерфейса

Я не знаю, почему это предупреждение не включено по умолчанию в IDEA, но все готово.

1 голос
/ 02 февраля 2011

AFAIK, вы в конечном итоге исчерпаете ресурсы на сервере базы данных из-за связанных файловых дескрипторов, ресурсов, необходимых для хранения результирующего набора, связанного с данным оператором и т. Д. Там могут быть интеллектуальные реализации драйвера / базы данных, которые гарантируют что, как только соединение закрыто, все связанные ресурсы освобождаются, но это не является частью спецификации, поэтому может в конечном итоге прийти и укусить вас в долгосрочной перспективе. Любая причина, почему ваши переопределяющие классы не могут закрыть наборы результатов и операторы, которые они используют?

0 голосов
/ 02 февраля 2011

Соединение с базой данных - не единственное, что связывает ваше приложение. На карту поставлены другие ресурсы.

Они освободятся в какой-то момент времени, если вы сами их не отпустите, но если можете это сделать, вам следует.

...