简体   繁体   English

Java连接未在Java Application中关闭

[英]Oracle connection not closing in Java Application

I have a connection leak in some older Java web applications which do not utilize connection pooling. 我在一些不使用连接池的旧Java Web应用程序中发生连接泄漏。 Trying to find the leak is hard because IT will not grant me access to v$session SELECT Count(*) FROM v$session; 试图找到泄漏很难,因为IT不会授予我访问v $ session SELECT Count(*) FROM v$session;

So instead I am trying to debug with System.out statements. 所以我试图使用System.out语句进行调试。 Even after closing the connection conn.close(); 即使在关闭连接conn.close(); when I print conn to the System log file it gives me the connection object name. 当我将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); 
    }

however if I also add conn = null; 但是,如果我也添加conn = null; below the conn.close(); conn.close();下面conn.close(); statement the connection now seems closed. 声明连接现在似乎已关闭。 So my question is does conn.close(); 所以我的问题是conn.close(); actually release my connection or do I also have to make it null to really release my connection. 实际上释放我的连接或我也必须使它为null以真正释放我的连接。 Like I said it is really hard for me to determine if the connection is actually released without being able to query v$session. 就像我说的那样,我很难确定连接是否实际发布而无法查询v $ session。 Is there snippet of java code which can give me my open connections?? 有没有java代码片段可以给我打开连接?

It's probably educational at this point because I plan to refactor these applications to use connection pooling but I'm looking for a quick bandaid for now. 这可能是教育性的,因为我计划重构这些应用程序以使用连接池,但我现在正在寻找一个快速的绑定。

The important part of the close is what's happening on the database side. 关闭的重要部分是数据库方面正在发生的事情。 It's the RDBMS that has to close that connection. 这是必须关闭该连接的RDBMS。 Calling the close() method is what communicates the message to the database to close the connection. 调用close()方法是将消息传递给数据库以关闭连接的方法。

Setting the connection to null doesn't instruct RDBMS to do anything. 将连接设置为null不会指示RDBMS执行任何操作。

Same logic applies to ResultSet, which is a cursor on the database side, and Statement. 相同的逻辑适用于ResultSet,它是数据库端的游标和Statement。 You need to close those in individual try/catch blocks in the finally block of the method that created them, in reverse order of creation. 您需要以创建它们的相反顺序关闭创建它们的方法的finally块中的各个try / catch块中的那些块。 Otherwise you'll see errors about "Max cursors exceeded". 否则,您将看到有关“超出最大游标数”的错误。

Setting the conn to null only breaks the reference link to the connection object, and has no influence on the connection being open or not. 将conn设置为null只会断开连接对象的引用链接,并且不会影响正在打开的连接。 If the connection is still open then the connection will still be referred to from inside the JDBC driver/connection pool etc... 如果连接仍处于打开状态,则仍将从JDBC驱动程序/连接池等内部引用连接...

Setting a variable to null is more telling the garbage collector that it is ok to clean up the original object when it wants to than anything else. 将变量设置为null更能说明垃圾收集器可以在需要时清除原始对象,而不是其他任何东西。

As others are saying, you've got two different concepts here: closing the connecting and tracking the connection in a variable. 正如其他人所说,这里有两个不同的概念:关闭连接并跟踪变量中的连接。

To close the connection, call conn.close() . 要关闭连接,请调用conn.close() This will not set the variable conn to null. 不会将变量conn设置为null。 You can test if the connection is open with conn.isClosed() . 您可以使用conn.isClosed()测试连接是否已打开。



If you don't care to track the connection in your code any more, you can conn = null . 如果您不再需要跟踪代码中的连接,则可以conn = null This does not immediately close the connection. 不会立即关闭连接。 I believe the connection will be automatically closed, based on the JDBC documentation : 我相信连接将根据JDBC 文档自动关闭:

Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be automatically released. 立即释放此Connection对象的数据库和JDBC资源,而不是等待它们自动释放。

If you choose to go this route, be aware that the garbage collector may not close your connection as quickly as you want, and you may have what appears to be a resource leak; 如果您选择这条路线,请注意垃圾收集器可能无法尽快关闭您的连接,并且您可能看到资源泄漏; reserved database locks won't be released until the connection is garbage collected. 在连接被垃圾回收之前,不会释放保留的数据库锁。 Certain drivers (I don't know if oracle is one) impose maximum limit to the number of connections that may exist at one time, so leaving open connections can also cause failures to connect, later in the program. 某些驱动程序(我不知道oracle是否为1)对一次可能存在的连接数施加了最大限制,因此保留打开的连接也会导致程序中的连接失败。

Connection leaks are a best. 连接泄漏是最好的。 I think a good strategy is to wrap the getting and releasing of connections in a couple of functions and then always get and release your connections through those functions. 我认为一个好的策略是在几个函数中包含连接的获取和释放,然后总是通过这些函数获取和释放连接。 Then you can have those functions maintain a list of all open connections, and do a stack trace on the caller of the allocate function. 然后,您可以让这些函数维护所有打开的连接的列表,并在allocate函数的调用者上执行堆栈跟踪。 Then have a screen that shows a list of all open connections and where they came from. 然后有一个屏幕,显示所有打开的连接列表以及它们来自何处。 Run this in a test environment, run around using a bunch of screens, then exit them all so all the connections SHOULD close, then bring up the screen that shows open connectoins, and the villain should be revealed. 在测试环境中运行它,使用一堆屏幕运行,然后全部退出以便所有连接应该关闭,然后调出显示打开connectoins的屏幕,并显示反派。

My explanation here is an educated guess. 我在这里的解释是一个有根据的猜测。

As a practice I have always set conn=null after the close. 作为一种做法,我总是在收盘后设置conn = null。 I believe when you do conn.close() you are telling the garbage collector that it's ready to be garbage collected. 我相信当你做conn.close()时,你告诉垃圾收集器它已经准备好被垃圾收集了。 However, it will be up to the garbage collection process to determine when to do so. 但是,将由垃圾收集过程决定何时这样做。

Also you can change your 你也可以改变你的

if(conn!=null) 如果(参数conn!= NULL)

to

if (conn.isClosed()) if(conn.isClosed())

.. ..

Is there snippet of Java code which can give me my open connections? 是否有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();
        }

Just a quick guess, assuming you are using Oracle. 只是快速猜测,假设您使用的是Oracle。 Sugession: Why don't you install jboss and set up connection pooling through there? Sugession:为什么不安装jboss并通过那里设置连接池?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM