简体   繁体   English

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

[英]How can I handle this exception within this method?

I have JDBC connection code similiar to the following from the Java JDBC tutorial: 我的JDBC连接代码类似于Java 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();
    }
  }

My problem with this way of handling to connection is that it closes the statement in the finally block and the method throws any SQLException that may occur. 这种处理连接方式的问题是,它关闭了finally块中的语句,并且该方法抛出了可能发生的任何SQLException。 I don't want to do that, because I want any problems handled within this class. 我不想这样做,因为我希望在此类中处理任何问题。 However, I do want that Statement#close() call in the finally block so that it is always closed. 但是,我确实希望在finally块中调用Statement#close()以便始终关闭它。

Right now I'm placing this code in a separate method that returns a HashMap of the fields returned to that the exception is handled in-class. 现在,我将这段代码放在一个单独的方法中,该方法返回一个HashMap ,其中包含要在类中处理异常的返回字段。 Is there another, possibly better way to handle this? 还有另一种可能更好的方法来处理此问题吗?

EDIT: The close() SQLException is the one I am concerned with. 编辑: close() SQLException是我关注的。 If possible I'd like to handle that within the method. 如果可能的话,我想在方法中处理。 I could write a try/catch in the finally, but that seems really awkward. 我可以在最后写一个try / catch,但这似乎很尴尬。

You have several problems: 您有几个问题:

  • You need to close the ResultSet explicitly. 您需要显式关闭ResultSet。 Some drivers are less forgiving about forgetting to close the ResultSet than others, it doesn't hurt anything to be sure to close it. 与其他驱动程序相比,某些驱动程序对忘记关闭ResultSet的宽容程度较小,确保关闭它不会对您造成任何伤害。

  • You ought to catch the SQLException thrown by the Statement.close, because it's not interesting and only serves to mask the interesting exception (if you have something in this method throw an exception, then the finally throws an exception on the way out, you get the exception from the finally block and lose the first exception). 您应该捕获Statement.close抛出的SQLException,因为它并不有趣,并且仅用于掩盖有趣的异常(如果此方法中的某些内容引发了异常,那么最后在出路时会引发异常,您会得到来自finally块的异常,并丢失第一个异常)。 There really isn't anything that you can do if a close method call throws an exception, just log it and go on, it is not something to be concerned about. 如果close方法调用引发异常,只是将其记录并继续运行,则实际上您无能为力,这无需担心。

  • You should give up on the idea of handling all sqlexceptions in this method, the SQLException thrown by statement.executeQuery is the one that is worthwhile and it ought to be propagated if something goes wrong. 您应该放弃在此方法中处理所有sqlexceptions的想法,由statement.executeQuery引发的SQLException是值得的,如果出现问题应该传播它。 It's likely other code in your application will want to know if your sql here succeeded or not and that's what throwing exceptions is for. 您的应用程序中的其他代码可能想知道您的sql是否成功,这就是抛出异常的目的。

Personally I'd suggest using a library like Ibatis or spring-jdbc for this. 我个人建议为此使用Ibatis或spring-jdbc之类的库。 JDBC is error-prone and tedious and it's better to take advantage of existing tools. JDBC容易出错且乏味,因此最好利用现有工具。

Here's how I usually handle this sort of resource stuff (note that whatever you do, you want a stmt != null check before you call stmt.close !): 这是我通常处理此类资源的方式(请注意, 无论您做什么,在调用stmt.close之前,您都需要stmt != null检查):

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) {
        }
    }
}

...although my finally block is usually much simpler than that because I have utility methods to encapsulate it. ...虽然我的finally块通常比这要简单得多,因为我有实用的方法来封装它。 (Specifically, it would probably look like this: (具体来说,它可能看起来像这样:

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

...where silentClose does the !null check and close call masking any exception and always returns null .) ...其中silentClose会执行!null检查并关闭屏蔽所有异常的调用,并始终返回null 。)

The key aspects of the above: 以上主要方面:

  1. The resource is either open, or null , never !null but closed (other than briefly between the close call and the null ; I'm assuming you won't be sharing this with other threads). resource是open或null ,从不!null而是封闭的(除了在close调用和null之间短暂进行;我假设您不会与其他线程共享此资源)。
  2. In the normal flow, I call close normally, without hiding any exception it may throw. 在正常流程中,我正常调用close ,而不隐藏它可能引发的任何异常。
  3. In the finally clause, if resource is !null , by definition some exception has occurred. finally子句中,如果resource!null ,则根据定义发生了一些异常。 Therefore, I should attempt to close resource , but prevent any exception from being thrown and masking the actual thing that went wrong. 因此,我应该尝试关闭resource ,但要防止引发任何异常并掩盖发生错误的实际情况。

In particular, I keep resource open only as long as I need it in the mainline code, for readability. 特别是,为了保持可读性,我仅在主线代码中需要时才保持资源开放。

There are other idioms for this: 还有其他成语:

  • The "rethrow" idiom: Always catch all exceptions, close your resources, and rethrow the exception. “重新抛出”成语:始终捕获所有异常,关闭资源,然后重新抛出异常。 Leads to a lot of unnecessary code in my view. 在我看来,这导致了很多不必要的代码。
  • The "success flag" idiom: Set a flag — possibly your return value — that tells you whether things worked, and then always clean up in finally . “成功标志”成语:设置一个标志-也许是你的返回值-告诉你的东西是否有效,然后总是收拾finally The thing is, you get the same duplication there that you get with my code, unless you're always going to hide exceptions on close . 事实是,除非您总是要在close上隐藏异常,否则您将得到与我的代码相同的重复。 Which brings us to: 这使我们能够:
  • The "I don't care about exceptions on close" idiom: Always do the "silent" close. “我不关心关闭时的异常”成语:始终关闭“静默”。 Gak. GAK。 :-) :-)

Applying the above to your code: 将以上内容应用于您的代码:

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);
    }
}

There are many ways to write JDBC initialization and closing to avoid boiler plate. 有许多方法可以编写JDBC初始化和关闭以避免样板。 However to answer your question, you could wrap stmt.close() in a try-catch block as below. 但是,要回答您的问题,您可以将stmt.close()包装在try-catch块中,如下所示。 Also, you need to close your result set. 另外,您需要关闭结果集。 (not written below) You may consider SpringDAO or Hibernate instead of JDBC to avoid checked exceptions. (以下未写)您可以考虑使用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 */}
    }
  }

As the method stands it does whatever 就目前的方法而言,它可以做什么

 JDBCTutorialUtilities.printSQLException(e);

does when the excepotion occurs, unless that method rethrows the exception you will just return from the method with no lasting knowledge that the exception occurred. 发生异常时会执行此操作,除非该方法重新抛出异常,否则您将在不持久知道发生异常的情况下从该方法返回。

You can put whatever code you like in the Exception block. 您可以将所需的任何代码放入Exception块。 The key question is what the caller of viewTable is supposed to do if an exception has happened. 关键问题是如果发生异常,viewTable的调用者应该怎么做。

You are presumably having code: 您大概有以下代码:

viewTable( /*etc*/);

doSomethingWith( price ); // for example

But that's no good if you've had an exception - price will not have been set. 但是,如果您有例外,那就不好了-价格不会确定。 So either 所以要么

a). 一种)。 in your exception block set a flag and then remember to check it 在您的异常块中设置一个标志,然后记得检查它

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

which to me is error prone, and defeats the whole point of Exceptions. 在我看来,这很容易出错,并且破坏了异常的全部观点。 or 要么

b). B)。 Don't catch the exception in viewTable (except maybe to log it, and rethrow, which I guess ma be what the utility methid is for). 不要在viewTable中捕获异常(除了可能将其记录并重新抛出,我想这可能是实用程序方法的目的)。

try {

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM