Java应用程序中的Oracle连接未关闭

Java应用程序中的Oracle连接未关闭,java,oracle,database-connection,Java,Oracle,Database Connection,我在一些不使用连接池的旧Java web应用程序中发现了连接泄漏。 尝试查找泄漏很困难,因为它不会授予我从v$session访问v$sessionSELECT Count(*)的权限 因此,我尝试使用System.out语句进行调试。即使在关闭连接后conn.close()当我将conn打印到系统日志文件时,它会给出连接对象的名称 try { Connection conn; conn.close() } catch (SQLException e) { } fin

我在一些不使用连接池的旧Java web应用程序中发现了连接泄漏。 尝试查找泄漏很困难,因为它不会授予我从v$session访问v$session
SELECT Count(*)的权限

因此,我尝试使用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语句连接现在似乎已关闭。所以我的问题是康涅狄格州关闭了吗;实际上释放我的连接,或者我也必须将其设为null才能真正释放我的连接。就像我说的,如果不能够查询v$session,我真的很难确定连接是否真的被释放了。是否有一段java代码可以让我打开连接


这可能是有教育意义的,因为我计划重构这些应用程序以使用连接池,但我现在正在寻找一个快速的bandaid。

将conn设置为null只会断开连接对象的引用链接,对连接是否打开没有影响。如果连接仍处于打开状态,则仍将从JDBC驱动程序/连接池等内部引用该连接


将变量设置为null更能告诉垃圾收集器,当它想清理原始对象时,可以清理原始对象,而不是其他任何东西。

我在这里的解释是一个有根据的猜测

作为实践,我总是在关闭后设置conn=null。我相信当你执行conn.close()时,你是在告诉垃圾收集器它已经准备好进行垃圾收集了。但是,何时这样做将取决于垃圾收集过程

你也可以改变你的想法

如果(conn!=null)

如果(连接已关闭())


..

结束的重要部分是数据库端发生的事情。必须关闭该连接的是RDBMS。调用close()方法将消息传递给数据库以关闭连接

将连接设置为null不会指示RDBMS执行任何操作


同样的逻辑也适用于ResultSet和语句,ResultSet是数据库端的游标。您需要在创建它们的方法的finally块中,以与创建相反的顺序关闭各个try/catch块中的那些。否则,您将看到关于“超过最大游标数”的错误。正如其他人所说,这里有两个不同的概念:关闭连接和跟踪变量中的连接

要关闭连接,请调用
conn.close()
。这不会将变量conn设置为null。您可以使用
conn.isClosed()
测试连接是否打开



如果您不想再跟踪代码中的连接,您可以
conn=null
。这不会立即关闭连接。我相信连接将根据JDBC自动关闭:

立即释放此连接对象的数据库和JDBC资源,而不是等待它们自动释放。
如果您选择走这条路线,请注意垃圾收集器可能没有按照您希望的速度关闭您的连接,并且您可能会出现资源泄漏;在连接被垃圾回收之前,不会释放保留的数据库锁。某些驱动程序(我不知道oracle是否是一个驱动程序)对一次可能存在的连接数施加了最大限制,因此保留打开的连接也可能会导致程序稍后的连接失败。

连接泄漏是最好的选择。我认为一个好的策略是将连接的获取和释放封装在几个函数中,然后始终通过这些函数获取和释放连接。然后,您可以让这些函数维护所有打开连接的列表,并对allocate函数的调用方进行堆栈跟踪。然后有一个屏幕,显示所有打开的连接以及它们来自何处的列表。在测试环境中运行此程序,使用一组屏幕四处运行,然后全部退出,以便所有连接都应关闭,然后打开显示打开的连接的屏幕,并显示恶棍。

是否有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并在那里建立连接池呢?

这是有道理的,我有点怀疑。好的,在调用close()之后,我尝试重用连接,得到了一个java.sql.SQLException:Closed connection。是的,你必须打开它,使用它,关闭它。我认为这有点做作,但是如果你在
try
块中声明
conn
,那么它随后就超出了范围,最后也在
块中。不过,我还是想知道是否有一个类变量正在跟踪,并且可能在某个地方跟踪中断并留下漏洞。@Alex,你是对的。。。在我的实际代码中,它是在try.yeah漏洞之外声明的……我的一些最新java web应用程序使用连接池,我可以看到那些正在工作的(当达到我的设置限制时发布)这些旧的java web应用程序-如果你可以将大量jsp文件中混合了HTML的java称为应用程序!!-在每个jsp中打开和关闭连接。如果我要修改这些jsp页面,我不妨使用connectionPool bean将其完全重构为MVC。我很好奇我的漏洞在哪里。我为一家“繁文缛节”公司工作——安装软件——哈!祝你好运,这里几乎不可能:)不确定你的代码将如何告诉我“所有”我的开放数据库连接。康涅狄格瑞德在哪里??如果我在代码conn=getConnection()中声明它;我将看到1个有效连接。我想看看