在选中的Exception上无法清除java.sql.Statement

时间:2012-12-31 14:41:51

标签: java jdbc findbugs

在我的方法show下面找到错误指定在检查异常时无法清除java.sql.Statement

    public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
    {
            CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
            int result=-1;

        String query=null;
        Connection con = null;
        PreparedStatement pstmt =null;
        try
        {
            CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
            CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );

            con = CaptivePortalDBConnection.getDataSource().getConnection();
            CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");              

            query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";

            CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);

            pstmt = con.prepareStatement(query);
            pstmt.setString(1,messageState); //<b>line 556</b>
            pstmt.setString(2,messageId);
            pstmt.setString(3,securityCodeHistoryId);
            pstmt.setString(4,phone);
            result = pstmt.executeUpdate();

            CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
        }
        catch (Exception e) {
            result = -1;
            CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e);
        }
        finally
        {
            CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
            try
            {
                if(pstmt!=null)
                    pstmt.close();
                if(con !=null)
                    con.close();

                CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");

            }
            catch(Exception e)
            {
                CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
            }
        }
    CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
    return result;
}

fail to cleanup java.sql.Statement

我在堆栈上找到很多链接,但没有一个能够解决我的问题(可能我无法正确理解它们)。任何帮助将不胜感激。

先谢谢..........

使用 @Mark 指定的解决方案更新我的finally块之后问题仍然存在

finally
{
    CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
    try {
        if(pstmt!=null)
            pstmt.close();
    } catch (Exception ex) {
        // Log, ignore, etc
    }
    try {
        if(con !=null)
            con.close();
    } catch (Exception ex) {
        // Log, ignore, etc
    }
    CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}

使用@Jon建议后,我的问题得到解决。最后解决的代码是::

public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
    {
            CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
            int result=-1;
            String query=null;
            Connection con = null;
            PreparedStatement pstmt =null;
            try
            {
                CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
                CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );

                con = CaptivePortalDBConnection.getDataSource().getConnection();
                CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");              

                query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";

                CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);
                try
                {
                    pstmt = con.prepareStatement(query);
                    pstmt.setString(1,messageState);
                    pstmt.setString(2,messageId);
                    pstmt.setString(3,securityCodeHistoryId);
                    pstmt.setString(4,phone);
                    result = pstmt.executeUpdate();
                }
                catch(SQLException e1)
                {
                    CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e1);
                }
                finally{
                    if(pstmt!=null)
                    pstmt.close();
                }

                CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
            }
            catch (SQLException e2) {
                result = -1;
                CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e2);
            }
            finally
            {
                CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
                try
                {
                    if(con !=null)
                        con.close();

                    CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");

                }
                catch(SQLException e)
                {
                    CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
                }
            }
        CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
        return result;
    }

4 个答案:

答案 0 :(得分:9)

看看这段代码:

if(pstmt!=null)
    pstmt.close();
if(con !=null)
    con.close();

现在考虑pstmt.close()可以抛出异常......这意味着con.close()不会被调用。

如果您使用的是Java 7,请改用try-with-resources语句,否则您应该为每个资源设置一个单独的try / finally块。

try {
   connection = ...;
   try {
      statement = ...;
   } finally {
      // Clean up statement
   }
} finally {
   // Clean up connection
}

我也强烈建议不要抓住毯子Exception - 最好抓住你可以实际处理的特定例外,并让其他例外传播起来堆栈。此外,您似乎使用整数值来表示您的方法的成功或失败 - 这不是惯用的Java;通常,异常是错误处理的首选。

答案 1 :(得分:1)

问题是如果pstmt.close()抛出异常,那么连接永远不会关闭。

要么不关闭finally中的语句(因为如果Statement关闭,则需要关闭Connection个对象的驱动程序),或者将两者放在他们自己的try..catch块中。例如:

finally
{
    CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
    try {
        if(pstmt!=null)
            pstmt.close();
    } catch (Exception ex) {
        // Log, ignore, etc
    }
    try {
        if(con !=null)
            con.close();
    } catch (Exception ex) {
        // Log, ignore, etc
    }
    CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}

答案 2 :(得分:0)

Firebug是正确的。

您应该使用单独包装调用关闭方法来关闭finally块中的所有SQL资源。

您可以使用实用程序类:

package persistence;

public class DatabaseUtils {
    // similar methods for ResultSet and Connection
    public static void close(Statement s) {
        try {
            if (s != null) {
                s.close();
            }
        } catch (SQLException e) {
            // Log the exception
        }       
    }
} 

在创建资源的方法中调用finally块中的close方法。

答案 3 :(得分:0)

尝试在单独的try / catch / finally块中清理/关闭资源,否则如果任何一个抛出异常,则其余部分将保持未闭合状态。