我从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,但这看起来真的很尴尬。
答案 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
。)
以上的关键方面:
resource
是开放的,或null
,从不!null
但已关闭(除了close
来电与null
之间的短暂关系;我'假设您不会与其他线程共享此内容。)close
,而不会隐藏它可能抛出的任何异常。finally
子句中,如果resource
为!null
,则根据定义会发生一些异常。因此,我应该尝试关闭resource
,但是要防止抛出任何异常并屏蔽出错的实际事件。特别是,只要我在主线代码中需要资源,我就会保持资源开放,以提高可读性。
还有其他成语:
finally
中清理。问题是,除非你总是隐藏close
上的例外,否则你会得到与我的代码相同的复制品。这将我们带到:将以上内容应用于您的代码:
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
}