PreparedStatement和ResultSet上的资源泄漏

时间:2018-01-17 16:23:24

标签: java eclipse jdbc memory-leaks

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

对我而言,看起来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;
    }

3 个答案:

答案 0 :(得分:2)

所以,你说当没有记录创建另一个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

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

答案 1 :(得分:2)

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

preparedstatement = con.prepareStatement(saveRule1);

preparedstatement = con.prepareStatement(saveRule2);

preparedstatement = con.prepareStatement(saveRule3);

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

preparedstatement.close(); 

类似的问题在于您的ResultSet。 您创建了2个实例,但只关闭了其中的一个。

答案 2 :(得分: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

可以更安全(多用户)和更好