2

我想知道 finally 块是否真的可以关闭资源;比如,数据库连接?

根据我们的架构师的说法,finally 块对于关闭数据库连接是不可靠的,尤其是在 Web 应用场景中。

根据理论,无论代码的执行状态如何,finally 块都必须在逻辑流程结束时运行。finally 块是最佳实践。

我正在开发使用 JDK-1.4、纯 SQL 查询并从连接池获取数据库连接的 Web 应用程序项目。大多数 SQL 语句都是嵌套语句,单个方法包含多个 Statement 和 ResultSet 对象。

在这种情况下,我对 finally 块持怀疑态度,因为根据测试,finally 块没有释放资源,而是 Web 应用程序正在获取更多连接。最后,Tomcat 5.5 每隔两三个小时就会挂掉一次。

然后,我在执行 SQL 操作后和 catch 块中删除了 finally 块并释放资源。之后,web 应用程序完美释放资源,tomcat 不再挂起。

因此,我对 finally 块的理论感到非常困惑。

这是代码片段,如果编码技术错误,请告知:

        ... .. . . .. . .. . . .. .. . 
    ........ . .. . . ... . .. . .

    Connection dbCon = null;
    Statement stmt1 = null;
    ResultSet rs1 = null;

    try {
        dbCon = DB.getConnection();

        stmt1 = dbCon.createStatement();            
        rs1  = stmt1.executeQuery("sql Query as String");

        while(rs1.next()){

            String col1 = rs1.getString("DB_COL_1");
            int col2 = rs1.getInt("DB_COL_2");
            String col3 = rs1.getString("DB_COL_3");

            if(col3 != null){   

                Statement stmt2 = null;
                ResultSet rs2 = null;

                try{
                    stmt2 = dbCon.createStatement();                                                        
                    rs2 = stmt2.executeQuery("sql Query as String");

                    ------- - ----

                    while(rs2.next()){
                        String col4 = rsTierMember.getString("DB_COL_4");

                        ... . .. . . . .....                                
                        . .. . .. . . . . . ..          
                    }

                    ... . .. .. ... .

                }catch(SQLException sqlExp){

                } catch (Exception e) { 

                }finally{
                    try{
                        if(rs2!=null)
                            rs2.close();
                        if(stmt2!=null)
                            stmt2.close();
                    }catch(Exception ex){}                                                                 
                }
            }

        }

         .... . .. .

    }catch (SQLException e) {

    } catch (Exception e) {     

    }finally{
        try{            
            if(rs1!=null)
                rs1.close();
            if(stmt1!=null)
                stmt1.close();
            if(dbCon!=null) 
                dbCon.close;                
        }catch(Exception ex){

        }
    }


    ...... . . . . . ...
    ... . .. . .. . . .. .
4

3 回答 3

12

我想知道 finally 块是否真的可以关闭资源;比如,数据库连接?

这取决于您所说的“可靠”是什么意思。

  • 如果 JVM 被硬中止(例如由于 JIT 中的错误),它可能不会执行
  • 如果 JVM 正在正常终止,它可能不会执行(参见 Harmeet 的回答)
  • 它不会执行它try块的内容永远挂起
  • 电脑突然断电不执行

在所有这些情况下,我希望数据库注意到连接的另一端已经消失了。

如果您的架构师有一个他们认为该块不会执行的特定finally场景,他应该提供该场景的示例,此时您几乎可以肯定能够证明他们是错误的。如果他们拒绝提供任何细节,则忽略它们,并向管理层建议他们应该开始寻找不那么迷信的建筑师。

在这种情况下,我对 finally 块持怀疑态度,因为根据测试,finally 块没有释放资源,而是 Web 应用程序正在获取更多连接。最后,Tomcat 5.5 每隔两三个小时就会挂掉一次。

听起来测试可能无效,或者您正在其他地方泄漏连接,或者您没有关闭连接。但是很容易验证:将日志记录在finally块中,以验证您希望释放资源的代码是否至少被调用。如果它被调用但没有释放连接,那么它不再是finally块的问题。

于 2012-08-22T16:21:06.673 回答
2

这是一种finally不会执行的情况:

public class FinallyDemo {    
    public static void main(String[] args) {
        try {
            System.exit(0);
        } catch (Exception ex) {
            System.out.println(ex);
        } finally {
            System.out.println("finally");
        }
    }
}

注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。(参考)

并考虑Jon Skeet因为它取决于场景......以及“可靠”对您意味着什么。

于 2012-08-22T16:26:01.697 回答
2

除了已经发布的出色答案之外,您的最后一个块有点错误

  try{            
        if(rs1!=null)
            rs1.close();
        if(stmt1!=null)
            stmt1.close();
        if(dbCon!=null) 
            dbCon.close;                
    }catch(Exception ex){

    }

如果rs1.close抛出异常会发生什么? stmt1并且dbCon没有关闭。

虽然它有点笨重,但它将确保在“正常”条件下关闭资源的最佳机会(不考虑其他帖子中提到的所有事情)

try {      
    rs1.close();
} catch (Exception exp) {}
try {      
    stmt1.close();
} catch (Exception exp) {}
try {      
    dbCon.close;                
}catch(Exception ex){}

不,我们不需要检查null,因为 try/catch 会处理它以供使用。这也意味着如果rs1.close失败,我们不在乎,我们仍然可以尽最大努力关闭其他资源。

至少记录这些异常是个好主意,以防万一

于 2012-08-22T20:24:37.463 回答