Java关闭连接和findbugs

在我们的代码中,我们通常使用以下模式:

Connection conn; try{ conn = getConnection(); //Do databasey stuff }catch(Exceptions that get thrown){ }finally{ try{ conn.close(); }catch(SQLException ex){ logger.error("Failed to cleanup database connection",ex); } } 

然而,findbugs不喜欢这个。 由于conn.close()可以抛出exception,因此无法保证关闭连接。 findbugs是否过于迂腐或是否有更好的方法来关闭数据库连接。

编辑:添加删除尝试捕获关闭。

你真正想做的是将“The Elite Gentleman”的答案与@edu.umd.cs.findbugs.annotations.SuppressWarnings( "OBL_UNSATISFIED_OBLIGATION" )注释结合起来。 如果你以下面的方式完成关闭方法(这是btw这样做的首选顺序),FindBugs似乎只是很高兴:

 ... }finally{ try{ resultSet.close(); }catch( SqlException e ){ //log error }finally{ try{ statement.close(); }catch( SqlException e ){ //log error }finally{ try{ connection.close(); }catch( SqlException e ){ //log error } } } } 

这是非常冗长的,如果没有其他原因,你可能不想这样做,因为你应该使用DBUtils.closeQuietly()方法(或创建自己的,你的调用)。 但是,FindBugs无法识别这一点(即使用库或您自己的方法)正确关闭资源并向您发出警告。 在这种情况下,这显然是误报 。 因此,必须确保它是您获得的唯一警告,然后禁用该方法的特定警告。

 @edu.umd.cs.findbugs.annotations.SuppressWarnings( "OBL_UNSATISFIED_OBLIGATION" ) public void doStuff( final Connection connection ){ try{ //Do databasey stuff }catch( SqlException e ){ //throw a glorious exception.... }finally{ DbUtils.closeQuietly( resultSet ); DbUtils.closeQuietly( statement ); DbUtils.closeQuietly( connection ); } 

这样,您可以使用几行代码清理资源,并避免使用FindBugs警告。

已经有一个实用程序可以完成@duffymo提到的:Apache的DbUtils 。

  • DbUtils.close(ResultSet);
  • DbUtils.close(Statement);
  • DbUtils.close(Connection);

APIDocs显示所有可用的方法。


更新

这是一个例子:

 import org.apache.commons.dbutils; Connection conn; try{ conn = getConnection(); //Do databasey stuff } catch(Exception e){ //throw a glorious exception.... } finally{ DbUtils.closeQuietly(conn); //This hides the SQLException thrown by conn.close(); //or //DbUtils.close(conn); } 

更新:正如ArtB所建议的那样,如果您最终关闭资源和连接并且findBugs是一个唠叨,您可以添加以下注释(在方法之上)。

 @edu.umd.cs.findbugs.annotations.SuppressWarnings("OBL_UNSATISFIED_OBLIGATION") 

是的,有更好的方法。

创建一个静态方法,在try / catch中包装close:

 public class DatabaseUtils { public static void close(Connection c) { try { if (c != null) { c.close(); } } catch (SQLException e) { // print or log stack trace } } // same for Statement and ResultSet } 

是的,你应该将你的关闭封装在try块中,但是有一种更聪明的方式。

 try { Connection c = getConnection(); try { //do stuff } finally { c.close(); } } catch (SQLException e) { //Catch exceptions } 

没有更好的方法,但如果你想确保捕获所有内容,请将模式修改为:

 Connection conn; try{ conn = getConnection(); //Do databasey stuff }catch(Exceptions that get thrown){ }finally{ try { conn.close(); } catch (SQLException se) { log.error("database problems..."); // do more stuff if you need to } } 

您可以通过使用Spring JDBCTemplate之类的东西来避免整个过程,它可以为您正确封装所有打开/关闭逻辑,简化代码,使其更清晰,更易于阅读(以及更可能是正确的)。

例如,将表中的某些列读入键值对列表(是的,丑陋的,但很容易理解):

  List> resultList = jdbcTemplate.query(query, new RowMapper>() { @Override public Map mapRow(ResultSet rs, int rownum) throws SQLException { Map row = new HashMap(); int colIndex = 0; row.put(CONTENTID_KEY, rs.getInt(++colIndex)); row.put(CONTENTTYPEID_KEY, rs.getInt(++colIndex)); row.put(DESCRIPTION_KEY, rs.getString(++colIndex)); row.put(CODE_KEY, rs.getString(++colIndex)); return row; } }); 

对于exception处理,请参见spring jdbcTemplate如何捕获exception?