2013-05-13 23 views
6

我正在创建JDBC Statement s和ResultSet s。如果抛出异常,确保对象关闭

Findbugs正确地指出,如果抛出异常,我不会close这些。

所以现在我有:

Statement stmt = null; 
ResultSet res = null; 
try { 
    stmt = ... 
    res = stmt.executeQuery(...); 
    ... 
} finally { 
    try { 
     if(res != null) 
      res.close(); // <-- can throw SQLException 
    } finally { 
     if(stmt != null) 
      stmt.close(); 
    } 
} 

(只有我有相当多的结果集,并准备报表等开放...所以我的finally小号嵌套是相当深)

有有以更好的方式确保大量结果集被关闭?我们认为这是一个非常好的设计决策,因为JDBC中的所有close方法都可能抛出SQLException,这使事情变得不必要的复杂化,在我看来。)

+3

为什么你在'finally'中有'try-finally'?应该有一些“catch”......对吧? – Bill 2013-05-13 12:51:33

+2

如何将所有语句和结果集存储在列表中并遍历列表? – reporter 2013-05-13 12:52:08

+2

@Bill:如果第一个'close'抛出异常。 – 2013-05-13 12:53:30

回答

4

如果您使用的是Java 7,那么您可以利用事实ResultSet扩展AutoCloseable并使用try-with-resources语句。

try (Statement sql = <WHATEVER>; 
    ResultsSet res = sql.executeQuery(<WHATEVER>)) { 
    // Use results 
} 

至少可以避开finally条款。

+2

可悲的是生产停留在1.6 :(但我喜欢这种方法,你已经告诉我,它会准确地解决这些问题。 – Will 2013-05-13 13:14:06

+1

@愿意编辑。*我想知道OP对于编辑和改进问题答案的难得程度* :-) – 2013-05-13 13:29:58

3

在我可以依赖Java 7的代码中,我可能会使用try-with-resources作为suggested by Duncan Jones

在我的老代码,还有我用两种方法:

首先是一组在静态辅助类的辅助方法,在这种形式:

public static final Statement quietClose(Statement s) { 
    if (s != null) { 
     try { 
      s.close(); 
     } 
     catch (Exception e) { 
      // Do some useful logging here 
     } 
    } 
    return null; 
} 

然后在你的finally块:

stmt = Helper.quietClose(stmt); 

第二种方法是使用一个LinkedList,添加的东西给它在我打开它们的顺序,然后有一个他以相反的顺序循环通过,并基本做到了上述。


在所有情况下,我努力保持方法足够短,以至于我不会得到需要关闭的18个不同的JDBC对象。 (我说我“努力”......我并不总是成功。)

0

要扩大reporter建议的内容,请保留要关闭的元素列表。创建一个方法来执行关闭,获得Throwable并返回Throwable。迭代收集任何返回的Throwables的列表并抛出第一个返回的列表。

private Throwable close(Closable c){ 
    try{ 
     c.cloase(); 
     return null; 
    } catch (Throwable t){ 
     return t; 
    }; 
} 

private void workMethod(){ 
    try{ 


    }finally{ 
     List<Throwable> ts = new ArrayList<Throwable>(); 
     for(Closable c : closables){ 
      Throwable T = close(c); 
      if (t != null) 
        ts.add(t); 
     } 

     if (!ts.isEmpty()) 
      throw ts.get(0); 
    } 
} 
2

A blog post by David M. Lloyd从几年前盖这口井,寻找解决方案和解决上直接创建的每个资源上面筑巢新try/finally的模式。在我们的例子中,这样的事情:

Statement stmt = null; 
ResultsSet res = null; 
try { 
    stmt = ... 
    try { 
     res = stmt.executeQuery(...); 
     ... 
    } finally { 
     try { 
      res.close(); 
     } catch (Throwable t) { 
      t.printStackTrace(); 
     } 
    } 
} finally { 
    try { 
     stmt.close(); 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
} 

如果你走这条路,这是一个好主意,也跟随大卫的意见,并创建可以在整个项目中使用一个安全的资源收盘方法。然后可以调用此方法来代替finally块中的try/catch块。

// put this anywhere you like in your common code. 
public static void safeClose(Closeable c) { 
    try { 
     c.close(); 
    } catch (Throwable t) { 
     // Resource close failed! There's only one thing we can do: 
     // Log the exception using your favorite logging framework 
     t.printStackTrace(); 
    } 
} 
3

不要自己写这个,请查看Apache Commons DbUtils.closeQuietly()

这将关闭ResultSets,StatementsConnections的组合,一路处理空值。它不会处理多个ResultSets,注意,但是否则很有用。