views:

319

answers:

2

When using a PreparedStatement in JDBC, should I close the PreparedStatement first or the Connection first? I just saw a code sample in which the Connection is closed first, but it seems to me more logical to close the PreparedStatement first.

Is there a standard, accepted way to do this? Does it matter? Does closing the Connection also cause the PreparedStatement to be closed, since the PreparedStatement is directly related to the Connection object?

+11  A: 

The statement. I would expect you to close (in order)

  1. the result set
  2. the statement
  3. the connection

(and check for nulls along the way!) If you use Spring JdbcTemplate (or similar) then that will look after this for you. Alternatively you can use Apache Commons DbUtils and DbUtils.close() or DbUtils.closeQuietly().

Brian Agnew
Indeed. Some JDBC drivers will throw an exception on closing a result set or statement after the connection is closed.
Yishai
That's correct. To the point: close the *resources* in **reversed order** as you acquired them.
BalusC
+2  A: 

The following procedures should be done (in order)

  • The ResultSet
  • The PreparedStatement
  • The Connection.

Also, it's advisable to close all JDBC related objects in the finally close to guarantee closure.

//Do the following when dealing with JDBC. This is how I've implemented my JDBC transactions through DAO....

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
  conn = ....
  ps = conn.prepareStatement(...);

  //Populate PreparedStatement
  rs = ps.executeQuery();

} catch (/*All relevant exceptions such as SQLException*/Exception e) {
  logger.error("Damn, stupid exception: " , e);
} finally {
if (rs != null) {
            try {
                rs.close();
                rs = null;
            } catch (SQLException e) {
                logger.error(e.getMessage(), e.fillInStackTrace());
            }
        }

        if (ps != null) {
            try {
                ps.close();
                ps = null;
            } catch (SQLException e) {
                logger.error(e.getMessage(), e.fillInStackTrace());
            }
        }

        try {
            if (conn!= null && !conn.isClosed()){
                if (!conn.getAutoCommit()) {
                    conn.commit();
                    conn.setAutoCommit(true);
                }
                conn.close();
                conn= null;
            }
        } catch (SQLException sqle) {
            logger.error(sqle.getMessage(), sqle.fillInStackTrace());
        }
}

You can see I've checked if my objects are null and for connection, check first if the connection is not autocommited. Many people fail to check it and realise that the transaction hasn't been committed to DB.

The Elite Gentleman
All of that finally boilerplate should be condensed into a utility method (for example `DBUtils.close(rs, ps, conn);`). Also the advice about autocommit depends on the situation. Sometimes when there is an exception you do not want to commit at all. Also, the effort of explicitly setting the reference to null is almost always unneeded, because it will get dereferenced when the method exits, which is hopefully very soon after this, otherwise the method is likely too long.
Yishai
@Yishai - thanks, I was wondering about that.
froadie
@Yishai, yes, I forgot to mention that if there are exceptions and autocommit is off, you can do a rollback...Thanks for showing this.
The Elite Gentleman