【问题标题】:Resource Leak on PreparedStatement and ResultSetPreparedStatement 和 ResultSet 上的资源泄漏
【发布时间】:2018-06-26 14:28:19
【问题描述】:

Eclipse 显示警告消息“资源泄漏,preparedstatement 未在以下位置关闭”

在我看来,finally 块负责关闭preparedstatement 和rs 对象。知道为什么 eclipse 仍然抱怨资源泄漏吗?

String ruleGrpId = null;
        int finalRuleID = 0;

        String saveRule1 = "INSERT INTO ..";
        String saveRule2 = "INSERT INTO ";

        String saveRule3 = "select ..._name = ?";

        PreparedStatement preparedstatement = null;
        ResultSet rs = null;

        try {
            if (objSomeRule.getRule() == 0) {

                preparedstatement = con.prepareStatement(saveRule1);
                preparedstatement.setString(1, ruleId);

                preparedstatement.executeUpdate();

                //Eclipse complains here
                preparedstatement = con.prepareStatement(saveRule2);

                preparedstatement.setInt(1, ruleID_2);
                preparedstatement.setString(2, ruleID_3);

                rs =  preparedstatement.executeQuery();

                if(rs.next()){
                    finalRuleID = rs.getInt(1);
                }else{
                    //complains here
                    preparedstatement = con.prepareStatement(saveRule3);
                    preparedstatement.setString(1, ruleID_4);
                    //complains here
                    rs =  preparedstatement.executeQuery();
                    if(rs.next()){
                        finalRuleID = rs.getInt("rulegroup_id");
                    }
                }
                objSomeRule.setRuleID(finalRuleID);

            }

        } finally {

            if(preparedstatement != null){
                preparedstatement.close();
            }

            if(rs != null){
                rs.close();
            }
        }

        return finalRuleID;
    }

【问题讨论】:

    标签: java eclipse jdbc memory-leaks


    【解决方案1】:

    您创建了 3 个不同的 PreparedStatement 实例:

    preparedstatement = con.prepareStatement(saveRule1);
    
    preparedstatement = con.prepareStatement(saveRule2);
    
    preparedstatement = con.prepareStatement(saveRule3);
    

    您的变量preparedStatement 仅保存您打开的最后一个变量, 而且您没有对您之前打开的其他人的引用。
    因此,在您的finally 部分中,您只关闭最后一个PreparedStatement

    preparedstatement.close(); 
    

    您的ResultSets 也有类似的问题。 您创建了 2 个实例,但只关闭了其中的 1 个。

    【讨论】:

    • 谢谢@Thomas,我现在明白了 :)
    【解决方案2】:

    变量preparedStatementrs 的重用可防止在变量的旧对象值上调用close()。 Try-with-resources 是一种巧妙的解决方案,因为 close() 会自动调用,即使在深度嵌套的 try 中引发异常或执行返回时也是如此。

        String ruleGrpId = null;
        int finalRuleID = 0;
        String saveRule1 = "INSERT INTO ..";
        String saveRule2 = "INSERT INTO ";
        String saveRule3 = "select ..._name = ?";
    
        if (objSomeRule.getRule() == 0) {
            try (PreparedStatement ps1 = con.prepareStatement(saveRule1)) {
                ps1.setString(1, ruleId);
                ps1.executeUpdate();
            }
            try (PreparedStatement ps2 = con.prepareStatement(saveRule2)) {
                ps2.setInt(1, ruleID_2);
                ps2.setString(2, ruleID_3);
    
                try (ResultSet rs2 =  ps2.executeQuery()) {
    
                    if (rs2.next()) {
                        finalRuleID = rs2.getInt(1);
                    } else {
                        try (Preparedstatement ps3 = con.prepareStatement(saveRule3)) {
                            ps3.setString(1, ruleID_4);
                            //complains here
                            try (ResultSet rs3 =  ps3.executeQuery()) {
                                if (rs3.next()) {
                                    finalRuleID = rs3.getInt("rulegroup_id");
                                }
                            }
                        }
                    }
                }
                objSomeRule.setRuleID(finalRuleID);
            }
        }
    

    如果最后一个 SELECT 查询打算检索先前 INSERT 的 AUTOINCREMENT ID,那么使用getGeneratedKeys 可以更安全(多用户)和更好地完成此操作

    【讨论】:

    • 感谢@JoopEggen,我将使用 try-with-reosurce 重新实现我的代码。我也在我的代码中使用了 getGeneratedKeys,但是在提取代码摘录粘贴到这里时,它被遗漏了。
    【解决方案3】:

    所以,你是说当没有记录时创建另一个preparedStatement。

     if(rs.next())
     {
          finalRuleID = rs.getInt(1);
     }
     else
     {
        //close here first
        if(preparedstatement != null)
        {
           preparedstatement.close();
        }
    
        if(rs != null){
           rs.close();
        }
    
        preparedstatement = con.prepareStatement(saveRule3);
        // your code
    

    但是,你还没有关闭前一个。我不完全确定,你为什么要这样做,但是,假设你需要这样做。然后,你应该先关闭前一个。

    【讨论】:

    • 谢谢@Ravi。您的建议很有帮助
    猜你喜欢
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2014-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2012-10-23
    相关资源
    最近更新 更多