140

I am getting a little confused. I was reading the below from Java Database Connectivity:

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    // It's important to close the statement when you are done with it
    stmt.close();
}

Do you not need to close the conn connection? What is really happening if the conn.close() doesn't occur?

I have a private web application I'm maintaining that doesn't currently close either form, but is the important one really the stmt one, the conn one, or both?

The site keeps going down intermittently, but the server keeps saying it's a database connection issue. My suspicion is that it's not being closed, but I don't know which, if any, to close.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
onaclov2000
  • 5,741
  • 9
  • 40
  • 54
  • It's always a best practice to close the connections on your own, without depending on other drivers and templates to handle closing. Failure of closing the connection will result in the sockets and resources open forever until a crash(no more resource scenario) or restart. – Arun Joseph Jun 10 '19 at 13:05

7 Answers7

224

When you are done with using your Connection, you need to explicitly close it by calling its close() method in order to release any other database resources (cursors, handles, etc.) the connection may be holding on to.

Actually, the safe pattern in Java is to close your ResultSet, Statement, and Connection (in that order) in a finally block when you are done with them. Something like this:

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

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* Ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* Ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* Ignored */}
    }
}

The finally block can be slightly improved into (to avoid the null check):

} finally {
    try { rs.close(); } catch (Exception e) { /* Ignored */ }
    try { ps.close(); } catch (Exception e) { /* Ignored */ }
    try { conn.close(); } catch (Exception e) { /* Ignored */ }
}

But, still, this is extremely verbose so you generally end up using an helper class to close the objects in null-safe helper methods and the finally block becomes something like this:

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

And, actually, the Apache Commons DbUtils has a DbUtils class which is precisely doing that, so there isn't any need to write your own.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 3
    Awesome help, thank you! I didn't catch or think about the conn != null statements. – onaclov2000 Feb 08 '10 at 22:17
  • 1
    @onaclov2000 Yes, `rs`, `ps`, `conn` may be `null` depending on where the code breaks. That's why this is known as the "safe" pattern. – Pascal Thivent Feb 08 '10 at 22:53
  • 13
    @Pascal Thivent: Actually we don't need to close all of them. "Core Java Volume two - Advanced Features" book has wrote: The `close` method of a `Statement` object automatically closes the associated `ResultSet` if the statement has an open result set. Similarly, the `close` method of the `Connection` class closes all `Statements` of the `Connection`. – Majid Azimi Jul 12 '11 at 12:13
  • 16
    @Majid: Unless it's a pooled connection. The statements would then leak away. – BalusC Jan 05 '13 at 21:33
  • 2
    @BalusC: Can u please explain what happens when a pooled connection is closed by using connection.close() method – Chaitanya Gudala Jan 10 '13 at 06:56
  • 2
    @Krnsa: usually, it's released back to the pool who in turn worry under the covers about testing/reaping the connections. – BalusC Jan 10 '13 at 11:44
  • 1
    FWIW, DbUtils is not exactly the same as the code above. DbUtils only catches SQLException. If the close() method threw any RuntimeException, DbUtils would allow that exception to escape, which is usually bad if called in a finally block. Of course most JDBC drivers *should* only throw SQLException. But I've been caught out by closeQuietly() methods not actually being "quiet" under all circumstances before. – npgall Oct 17 '14 at 11:01
  • what happens when, the program terminated and you didint call the close `function()`? – SüniÚr Feb 19 '15 at 13:46
  • What if I need to throw the SQL Exception instead? – Joey Pinto Jul 23 '17 at 12:21
  • 1
    Most of these answers are of course out of date. In the last few versions of Java you should use a try-with-resources block. See answer that explains this down below. – Joe Sep 13 '17 at 16:52
  • @BalusC you are wrong, pooling has no effect on closing, close on pooling connection will clean up THEN return to the pool. This is mandated by JDBC specs – Enerccio Mar 16 '18 at 12:08
73

It is always better to close the database/resource objects after usage. Better close the connection, resultset and statement objects in the finally block.

Until Java 7, all these resources need to be closed using a finally block. If you are using Java 7, then for closing the resources, you can do as follows.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

    // Statements
}
catch(....){}

Now, the con, stmt and rs objects become part of try block and Java automatically closes these resources after use.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yadu Krishnan
  • 3,492
  • 5
  • 41
  • 80
14

It is enough to close just Statement and Connection. There is no need to explicitly close the ResultSet object.

Java documentation says about java.sql.ResultSet:

A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.


Thanks BalusC for comments: "I wouldn't rely on that. Some JDBC drivers fail on that."

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Grigori A.
  • 2,628
  • 1
  • 21
  • 19
  • 29
    I wouldn't rely on that. Some JDBC drivers fail on that. E.g. Oracle with "Maximum open cursors exceeded", etc. Just explicitly close all opened resources, no excuses. – BalusC Jan 05 '13 at 21:41
  • 1
    I would rather not use drivers that do no conform to the specs then – Enerccio Mar 16 '18 at 12:09
  • 3
    As BalusC points out, it is good defensive programming to explicitly close the connection instead of hardwiring a dependency on a particular provider. – michaelok Jul 23 '18 at 17:23
14

Actually, it is best if you use a try-with-resources block and Java will close all of the connections for you when you exit the try block.

You should do this with any object that implements AutoClosable.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

The call to getDatabaseConnection is just made up. Replace it with a call that gets you a JDBC SQL connection or a connection from a pool.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joe
  • 376
  • 4
  • 13
11

Yes. You need to close the resultset, the statement and the connection. If the connection has come from a pool, closing it actually sends it back to the pool for reuse.

You typically have to do this in a finally{} block, such that if an exception is thrown, you still get the chance to close this.

Many frameworks will look after this resource allocation/deallocation issue for you. e.g. Spring's JdbcTemplate. Apache DbUtils has methods to look after closing the resultset/statement/connection whether null or not (and catching exceptions upon closing), which may also help.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 1
    When I insert a "finally" eclipse likes to highlight it telling me it's wrong. should this go after the catch blocks? – onaclov2000 Feb 08 '10 at 22:10
  • Yes. try{}catch{}finally{}. The catch{} is optional, btw. Just like the finally{} – Brian Agnew Feb 08 '10 at 22:11
  • I moved the "close" statements to the finally, but they're just saying "sqlexception", any suggestions? – onaclov2000 Feb 08 '10 at 22:12
  • 1
    close() throws a SQLException. You have to handle that. See DbUtils.closeQuietly() to handle this silently. – Brian Agnew Feb 08 '10 at 22:21
  • > What is really happening if the conn.close() doesn't occur? – Alex78191 Apr 15 '19 at 15:44
  • Re *"You typically have to do this in a finally{} block"*: Doesn't that happen way too late? Don't the close's need to be done directly? – Peter Mortensen Feb 06 '21 at 12:10
  • Not necessarily. It depends on what else goes on in your method. The reason why it should happen in a finally block is to ensure the connection is closed regardless of what’s happened. – Brian Agnew Feb 06 '21 at 12:12
7

Yes, you need to close Connection. Otherwise, the database client will typically keep the socket connection and other resources open.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Miller
  • 69,183
  • 25
  • 122
  • 167
  • 2
    ... until it exits. This ties down various finite resources on the client and server side. If a client does this kind of thing too much, it can cause problems for the client itself, the database service, and possibly even for other applications running on client or server machine. – Stephen C Feb 09 '10 at 00:53
2

Even better would be to use a Try With Resources block

try (Connection connection = DriverManager.getConnection(connectionStr, username, password)) {
    try (PreparedStatement statement = connection.prepareStatement(query)) {
        statement.setFetchSize(100);
        try (ResultSet resultSet = statement.executeQuery()) {
            List<String> results = new ArrayList<>();
            while (resultSet.next()) {
                String value = resultSet.getString(1);
                results.add(value);
                System.out.println(value);
            }
            return results;
        }
    }
}
reka18
  • 7,440
  • 5
  • 16
  • 37