如何在此方法中处理此异常?

时间:2010-11-16 14:56:36

标签: java jdbc sqlexception

我从Java JDBC教程中获得了类似以下的JDBC连接代码:

public static void viewTable(Connection con) throws SQLException {
    Statement stmt = null;
    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from " + dbName + ".COFFEES";
    try {
      stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(query);
      while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");
        System.out.println(coffeeName + "\t" + supplierID + "\t" + price + "\t" + sales + "\t" + total);
      }
    } catch (SQLException e ) {
      JDBCTutorialUtilities.printSQLException(e);
    } finally {
      stmt.close();
    }
  }

我对这种处理连接方式的问题是它关闭了finally块中的语句,并且该方法抛出了可能发生的任何SQLException。我不想这样做,因为我希望在这个类中处理任何问题。但是,我希望在finally块中调用Statement#close(),以便它始终关闭。

现在我将此代码放在一个单独的方法中,该方法返回返回的HashMap字段,以便在类中处理异常。还有另一种可能更好的方法来解决这个问题吗?

编辑:close() SQLException是我关注的那个。如果可能的话,我想在方法中处理。我可以在最后写一个try / catch,但这看起来真的很尴尬。

4 个答案:

答案 0 :(得分:3)

你有几个问题:

  • 您需要显式关闭ResultSet。有些司机对于忘记关闭ResultSet比对其他人更不宽容,不会伤害任何东西以确保关闭它。

  • 你应该捕获Statement.close抛出的SQLException,因为它不是很有趣并且只用于掩盖有趣的异常(如果你在这个方法中有东西抛出一个异常,那么最后会抛出异常出路,你从finally块获得异常并失去第一个异常)。如果close方法调用抛出一个异常,你可以做任何事情,只需记录并继续,这不是一件值得关注的事情。

  • 你应该放弃在这个方法中处理所有sqlexceptions的想法,由statement.executeQuery抛出的SQLException是值得的,如果出现问题它应该传播。您的应用程序中的其他代码可能会想知道您的sql是否成功,这就是抛出异常的原因。

我个人建议使用像Ibatis或spring-jdbc这样的库。 JDBC容易出错且乏味,最好利用现有工具。

答案 1 :(得分:1)

以下是我通常处理这类资源的方法(请注意你做的,在调用stmt != null之前需要进行stmt.close检查!):

SomeResource resource = null;
try {
    resource = /* ...get the resource... */;

    /* ...use the resource... */

    // Close it    
    resource.close();
    resource = null;

    // ...maybe do some post-processing... */

} catch (SomeException se) {
    // code to handle SomeException
} catch (SomeOtherException soe) {
    // code to handle SomeOtherException
} finally {
    if (resource != null) {
        try {
            resource.close();
        } catch (IOException e) {
        }
    }
}

...虽然我的finally块通常比这简单得多,因为我有实用程序方法来封装它。 (具体来说,它可能看起来像这样:

finally {
    resource = Utils.silentClose(resource);
}

...其中silentClose执行!null检查并关闭调用屏蔽任何异常并始终返回null。)

以上的关键方面:

  1. resource是开放的,或null,从不!null但已关闭(除了close来电与null之间的短暂关系;我'假设您不会与其他线程共享此内容。)
  2. 在正常流程中,我会正常调用close,而不会隐藏它可能抛出的任何异常。
  3. finally子句中,如果resource!null,则根据定义会发生一些异常。因此,我应该尝试关闭resource,但是要防止抛出任何异常并屏蔽出错的实际事件。
  4. 特别是,只要我在主线代码中需要资源,我就会保持资源开放,以提高可读性。

    还有其他成语:

    • “rethrow”成语:始终捕获所有异常,关闭资源并重新抛出异常。在我看来,导致了许多不必要的代码。
    • “成功标志”成语:设置一个标志 - 可能是您的返回值 - 告诉您事情是否有效,然后始终在finally中清理。问题是,除非你总是隐藏close上的例外,否则你会得到与我的代码相同的复制品。这将我们带到:
    • “我不关心近距离的例外”成语:始终做“无声”关闭。 GAK。 : - )

    将以上内容应用于您的代码:

    public static void viewTable(Connection con) throws SQLException {
        Statement stmt = null;
        ResultSet rs   = null; // <== You need this outside the try/catch block
        String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from " + dbName + ".COFFEES";
        try {
            stmt = con.createStatement();
            rs = stmt.executeQuery(query);
            while (rs.next()) {
                String coffeeName = rs.getString("COF_NAME");
                int supplierID = rs.getInt("SUP_ID");
                float price = rs.getFloat("PRICE");
                int sales = rs.getInt("SALES");
                int total = rs.getInt("TOTAL");
                System.out.println(coffeeName + "\t" + supplierID + "\t" + price + "\t" + sales + "\t" + total);
            }
    
            // Explicit close, allows for exception since we won't be hiding anything
            rs.close();
            rs = null;
            stmt.close();
            stmt = null;
    
            // Possible further processing...
    
        } catch (SQLException e ) {
            JDBCTutorialUtilities.printSQLException(e);
        } finally {
            // Close the ResultSet first, then the Statement
            rs   = Utils.silentClose(rs);
            stmt = Utils.silentClose(stmt);
        }
    }
    

答案 2 :(得分:1)

有许多方法可以编写JDBC初始化和关闭以避免锅炉板。但是要回答你的问题,你可以将stmt.close()包装在try-catch块中,如下所示。 此外,您需要关闭结果集。 (不在下面写) 您可以考虑使用SpringDAO或Hibernate而不是JDBC来避免检查异常。

public static void viewTable(Connection con) throws SQLException {
    Statement stmt = null;
    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from " + dbName + ".COFFEES";
    try {
      stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(query);
      while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");
        System.out.println(coffeeName + "\t" + supplierID + "\t" + price + "\t" + sales + "\t" + total);
      }
    } catch (SQLException e ) {
      JDBCTutorialUtilities.printSQLException(e);
    } finally {
      try{
         stmt.close();
      }catch(Exception e) { /*LOG to indicate an issue */}
    }
  }

答案 3 :(得分:0)

正如方法所表明的那样,无论做什么

 JDBCTutorialUtilities.printSQLException(e);

当异常发生时,除非该方法重新抛出异常,否则您将从方法返回,而不知道异常发生。

您可以在Exception块中放置您喜欢的任何代码。关键问题是如果发生异常,viewTable的调用者应该做什么。

你可能有代码:

viewTable( /*etc*/);

doSomethingWith( price ); // for example

但是,如果你有一个例外,这是不好的 - 价格不会被设定。所以要么

A)。在你的例外块中设置一个标志然后记住来检查它

viewTable( /*etc*/);
if (itAllWorked)
     doSomethingWith( price ); // for example

这对我来说很容易出错,并且打败了Exceptions的全部内容。或

B)。不要在viewTable中捕获异常(除非记录它,然后重新抛出,我猜这可能是实用程序methid的用途)。

try {

       viewTable()
       doSomethingWith(price):
       // all the normal flow
} catch (SqlException e) {
        //some reasnable action, which does not depend on things like proce
}