Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to close java PreparedStatements and ResultSets?

Consider the code:

PreparedStatement ps = null; ResultSet rs = null; try {   ps = conn.createStatement(myQueryString);   rs = ps.executeQuery();   // process the results... } catch (java.sql.SQLException e) {   log.error("an error!", e);   throw new MyAppException("I'm sorry. Your query did not work."); } finally {   ps.close();   rs.close(); } 

The above does not compile, because both PreparedStatement.close() and ResultSet.close() throw a java.sql.SQLException. So do I add a try/catch block to the finally clause? Or move the close statements into the try clause? Or just not bother calling close?

like image 319
MCS Avatar asked Nov 26 '08 17:11

MCS


People also ask

When should I close PreparedStatement?

Closing PreparedStatement ObjectIf you close the Connection object first, it will close the PreparedStatement object as well. However, you should always explicitly close the PreparedStatement object to ensure proper cleanup.

Should I close ResultSet and PreparedStatement?

You should explicitly close your Statement and PreparedStatement objects to be sure. ResultSet objects might also be an issue, but as they are guaranteed to be closed when the corresponding Statement/PreparedStatement object is closed, you can usually disregard it.

Does Java ResultSet need to be closed?

You should explicitly close Statements , ResultSets , and Connections when you no longer need them, unless you declare them in a try -with-resources statement (available in JDK 7 and after). Connections to Derby are resources external to an application, and the garbage collector will not close them automatically.

How do you close a statement in Java?

According to the Javadocs: Statement. close() Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.


2 Answers

In Java 7, you should not close them explicitly, but use automatic resource management to ensure that resources are closed and exceptions are handled appropriately. Exception handling works like this:

 Exception in try | Exception in close | Result -----------------+--------------------+----------------------------------------       No         |        No          | Continue normally       No         |        Yes         | Throw the close() exception       Yes        |        No          | Throw the exception from try block       Yes        |        Yes         | Add close() exception to main exception                  |                    |  as "suppressed", throw main exception 

Hopefully that makes sense. In allows pretty code, like this:

private void doEverythingInOneSillyMethod(String key)   throws MyAppException {   try (Connection db = ds.getConnection()) {     db.setReadOnly(true);     ...     try (PreparedStatement ps = db.prepareStatement(...)) {       ps.setString(1, key);       ...       try (ResultSet rs = ps.executeQuery()) {         ...       }     }   } catch (SQLException ex) {     throw new MyAppException("Query failed.", ex);   } } 

Prior to Java 7, it's best to use nested finally blocks, rather than testing references for null.

The example I'll show might look ugly with the deep nesting, but in practice, well-designed code probably isn't going to create a connection, statement, and results all in the same method; often, each level of nesting involves passing a resource to another method, which uses it as a factory for another resource. With this approach, exceptions from a close() will mask an exception from inside the try block. That can be overcome, but it results in even more messy code, and requires a custom exception class that provides the "suppressed" exception chaining present in Java 7.

Connection db = ds.getConnection(); try {   PreparedStatement ps = ...;   try {     ResultSet rs = ...     try {       ...     }     finally {       rs.close();     }   }    finally {     ps.close();   } }  finally {   db.close(); } 
like image 131
erickson Avatar answered Sep 27 '22 21:09

erickson


If you're really hand-rolling your own jdbc it definitely gets messy. The close() in the finally needs to get wrapped with its own try catch, which, at the very least, is ugly. You can't skip the close, although the resources will get cleared when the connection is closed (which might not be right away, if you're using a pool). Actually, one of the main selling points of using a framework (e.g. hibernate) to manage your db access is to manage the connection and result set handling so you don't forget to close.

You can do something simple like this, which at least hides the mess, and guarantees that you don't forget something.

public static void close(ResultSet rs, Statement ps, Connection conn) {     if (rs!=null)     {         try         {             rs.close();          }         catch(SQLException e)         {             logger.error("The result set cannot be closed.", e);         }     }     if (ps != null)     {         try         {             ps.close();         } catch (SQLException e)         {             logger.error("The statement cannot be closed.", e);         }     }     if (conn != null)     {         try         {             conn.close();         } catch (SQLException e)         {             logger.error("The data source connection cannot be closed.", e);         }     }  } 

and then,

finally {     close(rs, ps, null);  } 
like image 43
Steve B. Avatar answered Sep 27 '22 21:09

Steve B.