2

There are many steps involved in executing one SQL statement in Java:

  1. Create connection
  2. Create statement
  3. Execute statement, create resultset
  4. Close resultset
  5. Close statement
  6. Close connection

At each of these steps SQLException can be thrown. If we to handle all exception and release all the resources correctly, the code will will look like this with 4 levels of TRY stacked on the top of each other.

try {
     Connection connection = dataSource.getConnection();
     try {
           PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM myTable");
           try {
                ResultSet result = statement.executeQuery();
                try {
                     if (result.next()) {
                           Integer theOne = result.getInt(1);
                     }
                }
                finally {
                     result.close();
                }
           }
           finally {
                statement.close();
           }
     }
     finally {
           connection.close();
     }
}
catch (SQLException e) {
// Handle exception
}

Can you propose a better (shorter) way to execute a statement while still release all the consumed resources?

3
  • Wrap the entire thing in a try catch? Unless you want to know where specifically it failed. Commented Dec 5, 2012 at 14:38
  • If you wrap the whole block into try/catch and an exception gets thrown - you won't know which resources were consumed and need to be closed. Commented Dec 5, 2012 at 14:41
  • @user245106 I was being a bit facetious in my comment. Commented Dec 5, 2012 at 14:42

6 Answers 6

8

If you are using Java 7, the try with resources statement will shorten this quite a bit, and make it more maintainable:

try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(queryString); ResultSet rs = ps.execute()) {

} catch (SQLException e) {
    //Log the error somehow
}

Note that closing the connection closes all associated Statements and ResultSets.

Sign up to request clarification or add additional context in comments.

2 Comments

If you are using a connection pool, closing the connection may not actually close the Statement and the ResultSet.
Interesting -- I did not know that. Thanks for the tip.
4

Check out Apache Commons DbUtils, and in particular the closeQuietly() method. It will handle the connection/statement/result set closing correctly, including the cases where one or more are null.

An alternative is Spring JdbcTemplate, which abstracts a lot of work away from you, and you handle your database queries in a much more functional fashion. You simply provide a class as a callback to be called on for every row of a ResultSet. It'll handle iteration, exception handling and the correct closing of resources.

1 Comment

JdbcTemplate is rather nice, +1
0

I create a utility class with static methods I can call:

package persistence;

// add imports.

public final class DatabaseUtils {

    // similar for the others Connection and Statement
    public static void close(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e) {
            LOGGER.error("Failed to close ResultSet", e);
        }
    }
}

So your code would be:

     Integer theOne = null;
     Connection connection = null;
     PreparedStatement statment = null;
     ResultSet result = null;
     try {
         connection = dataSource.getConnection();
         statement = connection.prepareStatement("SELECT 1 FROM myTable");
         result = statement.executeQuery();
         while (result.next()) {
             theOne = result.getInt(1);
         }
    } catch (SQLException e) {
        // do something
    } finally {
        DatabaseUtils.close(result);
        DatabaseUtils.close(statement);
        DatabaseUtils.close(connection);
    }
    return theOne;

I'd recommend instantiating the Connection outside this method and passing it in. You can handle transactions better that way.

Comments

0
Connection connection = null;
PreparedStatement statement = null;
ResultSet result = null;
try {
     connection = dataSource.getConnection(); 
     statement = connection.prepareStatement("SELECT 1 FROM myTable");
     result = statement.executeQuery();
     if (result.next()) {
         Integer theOne = result.getInt(1);
     }
}
catch (SQLException e) { /* log error */ }
finally {           
     if (result != null) try { result.close(); } catch (Exception e) {/*log error or ignore*/}
     if (statement != null) try { statement.close(); } catch (Exception e) {/*log error or ignore*/}
     if (connection != null) try { connection.close(); } catch (Exception e) {/*log error or ignore*/}
}

Comments

0

Just close the Connection, this releases all resources*. You don't need to close Statement and ResultSet.

*just make sure you don't have any active transactions.

Comments

0

Your code can be shortened and written in this way...

Connection connection = dataSource.getConnection();
PreparedStatement statement = null;
ResultSet result = null;
try {
    statement= connection.prepareStatement("SELECT 1 FROM myTable");
    result = statement.executeQuery();
    if (result.next()) {
        Integer theOne = result.getInt(1);
    }
} catch (SQLException e) {
    // Handle exception

} finally {
    if(result != null) result.close();
    if(statement != null) statement.close();
    if(connection != null) connection.close();
}

2 Comments

This solution has a little issue. connection.close may also throw SQLException.
Good comment. This illustrate nicely that a simple resource mgmt issue is anything but

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.