如何正确清理Java中的JDBC资源?
清理JDBC资源时,什么被认为是最佳实践?为什么?我保持了示例的简短,因此只是清理结果集如何正确清理Java中的JDBC资源?,java,jdbc,Java,Jdbc,清理JDBC资源时,什么被认为是最佳实践?为什么?我保持了示例的简短,因此只是清理结果集 finally { if(rs != null) try{ rs.close(); } catch(SQLException ignored) {} } 对 finally { try{ rs.close(); } catch(Exception ignored) {} } 就我个人而言,我赞成第二种选择,因为它稍微短一点。对此,我们非常感谢您的任何意见 我看你的第二个(不常见的)版本没
finally
{
if(rs != null)
try{ rs.close(); } catch(SQLException ignored) {}
}
对
finally
{
try{ rs.close(); } catch(Exception ignored) {}
}
就我个人而言,我赞成第二种选择,因为它稍微短一点。对此,我们非常感谢您的任何意见 我看你的第二个(不常见的)版本没有问题
ResultSet rs = //initialize here
try {
// do stuff here
} finally {
try { rs.close(); }
catch(SQLException ignored) {}
}
- 通常情况下,rs不会为空,因此在极少数情况下会发生NPE。因此,我认为这里没有性能问题
- 如果
rs=null
null
,这可能会导致未屏蔽的泄漏
所以看起来是这样的:
finally {
try{rs.close(); }catch(Exception ignored){}
try{stmt.close();}catch(Exception ignored){}
try{conn.close();}catch(Exception ignored){}
}
。。。这仍然是可读和可理解的。但是,根据不改变一个共同的模式,我将坚持旧式的测试方法:<代码> null <代码>,在关闭的同时捕获<代码> SqLExcExo/<代码> < p>如果您正在编写一个长时间运行的应用程序,则应该考虑连接池。 ApacheDBCP项目为您做了大量这方面的工作。您还可以看看SpringJDBC或Hibernate之类的东西
Spring使用对象池,并添加了一些非常好的方法来抽象JDBC的缺点。我倾向于使用以下方法。我认为检查
null
很好,因为它显示了您的意图,即您确实意识到这些对象在极少数情况下可能为null。(空检查也比创建NullPointerException
要快)我还认为最好记录异常,而不是吞并它们。在close
失败的情况下,我想知道它并将其保存在日志文件中
finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
LOG.warn("Failed to close rs", e);
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
LOG.warn("Failed to close st", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
LOG.warn("Failed to close conn", e);
}
}
}
如果要经常执行此操作,请使用静态方法创建一个实用程序类来关闭ResultSet、语句和连接,而不是一次又一次地复制和粘贴此代码
使用,您可以非常简洁地执行此清理,如下所示:
finally {
DBUtils.closeQuietly(rs);
DBUtils.closeQuietly(st);
DBUtils.closeQuietly(conn);
}
正如其他人所指出的,JDBC资源(语句、结果集等)很少
null
。如果是的话,你手头的问题比NullPointerException
s更大。在这方面,NullPointerException
s将有助于提醒您JDBC驱动程序出现严重问题。如果您的JDBC驱动程序实际上为您提供了null
引用,那么在调用close()
之前典型的null
检查将隐藏问题
同样,并非所有JDBC驱动程序都严格遵循该规范。例如,当关联的语句
关闭时,某些驱动程序不会自动关闭结果集
。因此,您必须确保显式关闭结果集
及其语句
(叹气)
在实践中,我发现这项技术很有用(尽管它不是最漂亮的):
这项技术保证执行每个
close()
语句,从ResultSet
开始并向外执行<如果驱动程序向您提供null
引用,则仍然会抛出code>NullPointerExceptions,但出于开头解释的原因,我允许这样做<如果<代码>关闭()/代码>语句失败(我认为这是一件好事——我想知道是否出了问题),仍然会抛出代码> SqLExcExe>/Calp>S。 < P>这是我的JDK 6的方法。如果您有JDK 7+的话,最好使用我在这里描述的方法
- 它很短
- 它定义了一个可以静态导入的close方法
- 它避免了空的捕捉块
- 它处理可能发生的任何SQLException(即使在getConnection或close方法中)
- 它是零安全的
String query = "select COF_NAME, PRICE from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
float price = rs.getFloat("PRICE");
System.out.println(coffeeName + ", " + price);
}
}
try语句确保在语句末尾关闭每个资源。请参见不要考虑第二个选项-它也可以用于关闭流。顺便说一句-我喜欢你的名字,因为
忽略了
例外,我会记住:-)不管怎样,忘了“保持示例简短”:-)我推荐Vickie在下面的回复。期望异常作为正常代码流的一部分抛出从来都不是一个好的实践。在第二个首选块中,您依赖异常来处理空ResultSet的情况,而不是自己检查。如果ResultSet初始化返回错误(如果数据库配置错误或无响应),会发生什么情况?@Jean应该发生什么?在这种情况下,它不需要关闭。+1表示没有使用null
s执行愚蠢的操作-1用于您的异常处理。@Tom这不是我的异常处理:)帖子只是避免以相同的方式处理NPE和SQLException。您可以在关闭每个异常之前使用Logger。我想你知道这一点,但还有一次——最糟糕的一次<代码>空愚蠢。吞咽异常。第7项:避免终结器(有效的Java)我知道它与final不同,感谢你的for(;;){print('!')}+1没有对null
s做一些愚蠢的事情-1对于您的异常处理,以及对于如何初始化三个局部变量显得有点困惑。@Tom-这只是对OPs建议(版本2)所暗示的后果的评估。我想这已经足够清楚了……即使可以忽略这些罪行,你最终还是合并了块<代码>最后
块不会互相挤压。我就是这样做的。我不在“finally”catch块中做任何日志记录。我倾向于在catch块中添加日志记录
PreparedStatement statement = connection.prepareStatement("...");
try {
ResultSet results = statement.executeQuery();
try {
while (results.next()) {
// ...
}
} finally {
results.close();
}
} finally {
statement.close();
}
private void querySomething() {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
// get connection
// prepare statement
// execute query
// and so on
} catch (SQLException e) {
throw new MyException("Error while talking to database", e);
} finally {
close(connection, statement, rs);
}
}
// useful because you probably have more than one method interacting with database
public static void close (Connection connection, Statement statement, ResultSet rs) {
if (rs != null) {
try { rs.close(); } catch (Exception e) { _logger.warning(e.toString()); }
}
if (statement != null) {
try { statement.close(); } catch (Exception e) { _logger.warning(e.toString()); }
}
if (connection != null) {
try { connection.close(); } catch (Exception e) { _logger.warning(e.toString()); }
}
}
String query = "select COF_NAME, PRICE from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
float price = rs.getFloat("PRICE");
System.out.println(coffeeName + ", " + price);
}
}
public static void close(Statement... statements) {
for (Statement stmt : statements) {
try {
if (stmt != null)
stmt.close();
} catch (SQLException se) {
}// nothing we can do
}
}
public static void close(Connection conn) {
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
}// nothing we can do
}
public static void close(ResultSet rs) {
try {
if (rs != null)
rs.close();
} catch (SQLException se) {
}// nothing we can do
}