我在一些不使用连接池的旧Java Web应用程序中发生了连接泄漏。
试图找到泄漏很难,因为IT不会授予我访问v $ session SELECT Count(*) FROM v$session;
所以我试图使用System.out语句进行调试。即使在我将conn打印到系统日志文件时关闭连接conn.close();
,它也会为我提供连接对象名称。
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();实际上释放我的连接或我也必须使它为null以真正释放我的连接。就像我说的那样,我很难确定连接是否实际发布而无法查询v $ session。是否有java代码片段可以给我打开连接?
此时可能很有教育意义,因为我计划重构这些应用程序以使用连接池,但我现在正在寻找快速绑定。
答案 0 :(得分:6)
结束的重要部分是数据库方面正在发生的事情。这是必须关闭该连接的RDBMS。调用close()方法是将消息传递给数据库以关闭连接。
将连接设置为null不会指示RDBMS执行任何操作。
相同的逻辑适用于ResultSet,它是数据库端的游标和Statement。您需要以创建它们的相反顺序关闭创建它们的方法的finally块中的各个try / catch块中的那些块。否则,您将看到有关“超出最大游标数”的错误。
答案 1 :(得分:4)
将conn设置为null只会断开连接对象的引用链接,并且不会影响正在打开的连接。如果连接仍处于打开状态,则仍将从JDBC驱动程序/连接池等内部引用连接...
将变量设置为null更能说明垃圾收集器可以在需要时清理原始对象,而不是其他任何东西。
答案 2 :(得分:3)
正如其他人所说,这里有两个不同的概念:关闭连接并跟踪变量中的连接。
要关闭连接,请致电conn.close()
。此不会将变量conn设置为null。您可以使用conn.isClosed()
测试连接是否已打开。
如果您不想再跟踪代码中的连接,可以conn = null
。此不会立即关闭连接。我相信连接将根据JDBC documentation:
立即释放此Connection对象的数据库和JDBC资源,而不是等待它们自动释放。
如果您选择这条路线,请注意垃圾收集器可能无法尽快关闭您的连接,并且您可能看到资源泄漏;在连接被垃圾回收之前,不会释放保留的数据库锁。某些驱动程序(我不知道oracle是否为1)对一次可能存在的连接数施加了最大限制,因此保留打开的连接也可能导致连接失败,稍后在程序中。
答案 3 :(得分:1)
连接泄漏是最好的。我认为一个好的策略是在几个函数中包含连接的获取和释放,然后总是通过这些函数获取和释放连接。然后,您可以让这些函数维护所有打开的连接的列表,并在allocate函数的调用者上执行堆栈跟踪。然后有一个屏幕,显示所有打开的连接列表以及它们来自何处。在测试环境中运行,使用一堆屏幕运行,然后退出所有连接应该关闭,然后打开显示打开connectoins的屏幕,并显示恶棍。
答案 4 :(得分:0)
我在这里的解释是一个有根据的猜测。
作为一种练习,我总是在收盘后设置conn = null。我相信当你做conn.close()时,你告诉垃圾收集器它已经准备好被垃圾收集了。但是,将由垃圾收集过程决定何时这样做。
您也可以更改
如果(conn将!= NULL)
到
if(conn.isClosed())
...
答案 5 :(得分:0)
是否有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。 Sugession:为什么不安装jboss并通过那里设置连接池?