Соединение Oracle не закрывается в приложении Java

У меня есть утечка соединения в некоторых старых веб-приложениях Java, которые не используют пул соединений. Попытка найти утечку затруднена, потому что ИТ-отдел не предоставит мне доступ к v$session SELECT Count(*) FROM v$session;

Поэтому вместо этого я пытаюсь выполнить отладку с помощью операторов System.out. Даже после закрытия соединения conn.close();, когда я печатаю conn в файл системного журнала, он дает мне имя объекта соединения.

try { 
    Connection conn;
    conn.close() 
    } 
catch (SQLException e) { }
finally { 
    if (conn != null) {
        try {
           System.out.println("Closing the connection"); 
           conn.close();
           }
        catch (Exception ex) 
            {
            System.out.println("Exception is " + ex); 
            }
     }
 }
// I then check conn and it is not null and I can print the object name.
    if (conn != null) {
            System.out.println("Connection is still open and is " + conn); 
    }

однако, если я также добавлю conn = null; под оператором conn.close();, соединение теперь будет закрыто. Итак, мой вопрос: conn.close(); на самом деле освободить мое соединение, или мне также нужно сделать его нулевым, чтобы действительно освободить мое соединение. Как я уже сказал, мне очень сложно определить, действительно ли соединение разорвано, не имея возможности запросить v$session. Есть ли фрагмент кода Java, который может дать мне мои открытые соединения??

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


person jeff    schedule 22.09.2010    source источник
comment
Я предполагаю, что это немного надумано, но если вы объявляете conn внутри блока try, то впоследствии это выходит за рамки, а также в блоке finally. Тем не менее, мне интересно, есть ли у вас переменная класса, которую вы затеняете, и, возможно, где-то затенение нарушается и оставляет утечку.   -  person Alex Poole    schedule 23.09.2010
comment
@ Алекс, ты прав ... в моем реальном коде это объявлено вне попытки.   -  person jeff    schedule 23.09.2010


Ответы (6)


Важной частью закрытия является то, что происходит на стороне базы данных. Это РСУБД должна закрыть это соединение. Вызов метода close() — это то, что передает сообщение в базу данных, чтобы закрыть соединение.

Установка для соединения значения null не указывает РСУБД что-либо делать.

Та же логика применима к ResultSet, который является курсором на стороне базы данных, и к оператору. Вам нужно закрыть их в отдельных блоках try/catch в блоке finally метода, создавшего их, в порядке, обратном созданию. В противном случае вы увидите ошибки «Превышено максимальное количество курсоров».

person duffymo    schedule 22.09.2010
comment
Это имеет смысл и было своего рода моим подозрением. Итак, после вызова close() я попытался повторно использовать соединение и получил java.sql.SQLException: Closed Connection. - person jeff; 23.09.2010
comment
Да, вы должны открыть его, использовать его, закрыть его. - person duffymo; 23.09.2010

Установка для conn значения null только разрывает ссылку на объект соединения и не влияет на то, открыто соединение или нет. Если соединение все еще открыто, то на него все равно будет ссылаться драйвер JDBC/пул соединений и т.д.

Установка переменной в null больше говорит сборщику мусора, что можно очистить исходный объект, когда он этого хочет, чем что-либо еще.

person Peter Tillemans    schedule 22.09.2010

Как говорят другие, здесь у вас есть две разные концепции: закрытие соединения и отслеживание соединения в переменной.

Чтобы закрыть соединение, позвоните по номеру conn.close(). Это не установит для переменной conn значение null. Вы можете проверить, открыто ли соединение с помощью conn.isClosed().



Если вам больше не нужно отслеживать соединение в коде, вы можете conn = null. Это не немедленно закрывает соединение. Я считаю, что соединение будет автоматически закрыто на основе JDBC документация :

Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be automatically released.

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

person atk    schedule 22.09.2010

Утечки соединения лучше всего. Я думаю, что хорошая стратегия состоит в том, чтобы обернуть получение и освобождение соединений в пару функций, а затем всегда получать и освобождать ваши соединения через эти функции. Затем вы можете заставить эти функции поддерживать список всех открытых соединений и выполнять трассировку стека для вызывающей стороны функции выделения. Затем появится экран со списком всех открытых подключений и их происхождением. Запустите это в тестовой среде, побегайте, используя кучу экранов, затем закройте их все, чтобы все соединения ДОЛЖНЫ были закрыться, затем откройте экран, показывающий открытые соединения, и злодей должен быть раскрыт.

person Jay    schedule 22.09.2010
comment
да, утечки воняют .... Некоторые из моих последних веб-приложений java используют пул соединений, и я вижу, как они работают (выпускают при достижении установленного предела). Эти старые веб-приложения java - если вы можете вызвать java, смешанный с HTML, в тонне jsp подает заявку!! - открывать и закрывать соединения в каждом jsp. Если я собираюсь изменить эти jsp-страницы, я мог бы также провести полный рефакторинг в MVC с bean-компонентом connectionPool. Мне интересно, где моя утечка, хотя. - person jeff; 23.09.2010

Мое объяснение здесь является обоснованным предположением.

На практике я всегда устанавливал conn=null после закрытия. Я считаю, что когда вы выполняете conn.close(), вы сообщаете сборщику мусора, что он готов к сборке мусора. Однако процесс сборки мусора должен определить, когда это делать.

Также вы можете изменить свой

если (соединение! = ноль)

to

если (conn.isClosed())

..

person CoolBeans    schedule 22.09.2010

Есть ли фрагмент кода Java, который может дать мне мои открытые соединения?

Statement smt = null;
    ResultSet rs = null;
    try { 
        // Create Statement from connection
        smt = conn.createStatement();
        // Execute Query in statement 
        rs = stmt.executeQuery("SELECT 1 FROM Dual");

        if (rs.next()) {
            return true; // connection is valid
        }
        catch (SQLException e) {
            // Some sort of logging
            return false;
        }
        finally {
            if (smt != null) smt.close();
            if (rs != null) rs.close();
        }

Просто быстрое предположение, если вы используете Oracle. Предложение: почему бы вам не установить jboss и не настроить там пул соединений?

person sjt    schedule 22.09.2010
comment
Я работаю на бюрократическую корпорацию - установка программного обеспечения - ха! Удачи. Здесь почти невозможно :) - person jeff; 23.09.2010
comment
не уверен, как ваш код скажет мне ВСЕ мои открытые соединения с БД. Где наклеен конн?? И если я объявлю это в вашем коде conn = getConnection(); Я увижу 1 действительное соединение. Я хочу увидеть что-то вроде SELECT Count(*) FROM v$session, но он не предоставит мне доступ к v$session - person jeff; 23.09.2010
comment
Мой код является альтернативой conn.isClosed(), но я думаю, что здесь он вам не поможет. Я думаю, что здесь есть две концепции, как упоминали некоторые другие: одна - это объект, которому присваивается нулевое значение и который подвергается сборке мусора в следующем цикле сборки мусора, а другой - метод close() объектов Connection, немедленно освобождающий соединение JDBC. Если вы определяете, что соединение открыто, проверяя, присутствует ли объект соединения, на мой взгляд, это может быть ложным срабатыванием. - person sjt; 23.09.2010