How to Correctly Close Resources

前端 未结 6 1418
孤独总比滥情好
孤独总比滥情好 2020-12-09 16:48

As I was cleaning up some code, FindBugs pointed me to a bit of JDBC code that uses Connection, CallableStatement, and ResultSet objects. Here\'s a snippet from that code:

相关标签:
6条回答
  • 2020-12-09 17:13

    You only have to close the Connection.

    try
    {
        cStmt.close();
    }
    catch(Exception e)
    {
        /* Intentionally Swallow Exception */
    } 
    

    From docs.oracle.com:

    A Statement object is automatically closed when it is garbage collected. When a Statement object is closed, its current ResultSet object, if one exists, is also closed.

    Calling close() on a Connection releases its database and JDBC resources.

    0 讨论(0)
  • 2020-12-09 17:26

    Use Lombok's cleanup, if you can:

    @Cleanup
    Connection c = ...
    @Cleanup
    statement = c.prepareStatement(...);
    @Cleanup
    rs = statement.execute(...);
    

    This works translates to three nested try-finally blocks and works fine with exception. Never ever swallow an exception without a very good reason!

    An alternative:

    Write an own utility method like this:

    public static void close(ResultSet rs, Statement stmt, Connection con) throws SQLException {
        try {
            try {
                if (rs!=null) rs.close();
            } finally {
                if (stmt!=null) stmt.close();
            }
        } finally {
            if (con!=null) con.close();
        }
    }
    

    and use it in

    try {
        Connection con = ...
        Statement stmt = ...
        ResultSet rs = ...
    } finally {
        close(rs, stmt, con);
    }
    

    and let the Exception bubble up or handle it as you want.

    0 讨论(0)
  • 2020-12-09 17:28

    Well basically that is what you do except you first of all don't necessarily swallow the exception (you can null check and at least LOG the exception). Second, you can set up a nice utility class with things like

    public static void close(ResultSet rs) {
       try { if (rs != null) rs.close();
       } catch (SQLException (e) {
          log.error("",e);
       } 
    
    }
    

    Then you just static import that class.

    your finally becomes something like

    finally {
         close(resultset);
         close(statement);
         close(connection);
    }
    

    which really isn't that hideous.

    0 讨论(0)
  • 2020-12-09 17:31

    You can wrap one block into another block:

    try{
      Connection c = ...
        try{
          statement = c.prepareStatement(...);
          try{
            rs = statement.execute(...);
          }finally{
            rs.close();
          }
        }finally{
          statement.close()
        }
      }finally{
        c.close();
      }
    }catch(SQLException e){}
    

    Use the lowermost catch-block for everything that might crop up

    0 讨论(0)
  • 2020-12-09 17:34

    The only way I know to hide all that ugly try-catch boilerplate code is to utilize something like Spring's JBDC Template.

    0 讨论(0)
  • 2020-12-09 17:39

    I think the best answer has already being mentioned, but I thought it could be interesing to mention that you could consider the new JDK 7 feature of autoclosable resources.

    try{
        try(Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/hrdb", "obiwan", "kenobi"); 
            Statement stm = conn.createStatement(); 
            ResultSet rs = stm.executeQuery("select name from department")) {
    
            while(rs.next()){
                System.out.println(rs.getString("name"));
            }
    
        } 
    }catch(SQLException e){
        //you might wanna check e.getSuppressed() as well
        //log, wrap, rethrow as desired.
    }
    

    Not all of us can migrate to JDK 7 now, but for those who can start playing with the developer preview, this offer an interesting way of doing things and certainly may deprecate other approaches in the near future.

    0 讨论(0)
提交回复
热议问题