最后块是否真的可靠关闭资源?更新了代码段

时间:2012-08-22 16:17:20

标签: java web-applications jdbc

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

根据我们的架构师的说法,最后阻止关闭数据库连接是不可靠的,尤其是在Web应用程序场景中。

根据理论,无论代码的执行状态如何,最后块必须在逻辑流程的末尾运行。最后,阻止是最好的做法。

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

在这种情况下,我对最终阻止持怀疑态度,因为根据测试,最后阻止不释放资源而是Web应用程序正在获取更多连接。最后,Tomcat 5.5每隔两三个小时就被吊死。

然后,我删除了finally块并在执行SQL操作之后和catch块中释放资源。之后,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){

        }
    }


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

3 个答案:

答案 0 :(得分:12)

  

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

这取决于“可靠”的含义。

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

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

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

  

在这种情况下,我对最终阻止持怀疑态度,因为根据测试,最后阻止不释放资源而是Web应用程序正在获取更多连接。最后,Tomcat 5.5每隔两三个小时就被吊死。

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

答案 1 :(得分: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代码被中断或终止,最后   即使作为一个整体的应用程序,块也可能无法执行   继续。(reference)

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

答案 2 :(得分:2)

除了已经发布的优秀答案之外,你最后一个块是有点不对的

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

    }

如果rs1.close抛出异常会怎样? stmt1dbCon未关闭。

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

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

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

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