Follow up question to Closing Database Connections in Java
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();
}
conn.close();
I know that conn.close() is necessary but do not know why. Won't the garbage collector free the connection object (and with it release every handler stored in it that points to the database), once the method call is over?
Won't the garbage collector free the connection object (and with it release every handler stored in it that points to the database), once the method call is over?
It doesn't. The JDBC driver retains a reference to to connection, so it is not cleaned up unless you can close().
BTW creating a database connection is very expensive, so you will want to recycle your connections where possible.
You're trusting that you're the only one who has references to the Connection. The driver probably keeps track of them, and it won't let go of a connection that hasn't been closed. That's why you always need to close all more complicated resources (connections, streams, etc.).
Related
if i do close to connection database instead if i do close my resultSet ,what happend ?
I did write example to under.
For example.
Database.java
public class Database{
try{
Connection con;
PreparedStatement statement;
ResultSet resultSet;
public static void main{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/database";
String _username="root";
String _password = "password";
Connection db = DriverManager.getConnection(url,_username,_password);
String sqlQuery = "select * from category";
statement = db.prepareStatement(sqlQuery);
resultSet = statement .executeQuery();
while(resuletSet.next()){
......
}
// i dont close connect.
resultSet.close();
//what happen then it? connection.close() , will it be automatically down ?
}catch(Exception e){
e.printStackTrace();
}
}
}
You're right to close your ResultSet carefully. Leaving those objects around after you finish with them is definitely a way to get memory leaks.
You should also close your Connection objects when you no longer need them. If your Java program terminates any Connection objects you still have open are closed, automatically. If no queries are in progress on those objects then the MySQL server closes the connection and cleans up when Java abandons the connection.
Java since version 7 has a way to manage this cleanly. You can do
try (Connection db = DriverManager.getConnection(url,_username,_password)){
//use the connection object
...
try (ResultSet result = stmt.ExecuteQuery(whatever)) {
// use the resultset
} catch (whatever) { whatever }
}
catch(whatever) { whatever }
This is is a nice way to avoid these leaks; the Connection and ResultSet objects get closed automatically at the end of the try / catch block just as if they were closed in a finally{} clause. It's called automatic resource block management.
Yes, close Connections when you're done with them. If you open a lot of Connection objects without closing them, two bad things happen:
Less bad: your Java program's RAM will leak.
More bad: your MySQL server's connection slots will fill up and it will start rejecting new connections. Client bugs which use up server resources are generally bad bugs.
Failing to close Connections can be pernicious, because typical programs don't use as many of them as ResultSets. So it takes longer to accumulate lots of unclosed connections, and you may not detect the problem while testing. Testers should log into the MySQL server directly and run the SHOW PROCESSLIST; command during system testing to see if unclosed Connections are accumulating.
Close your ResultSets and your Connections.
Statement statement;
Connection connection;
I am closing connection after every database operation as below.
connection.close();
i created statement object as below.
connection.createStatement(....)
Do i need to close satement also similar to connection closing?
I mean do i need to call statement.close();?
What will happen if it is not called?
Thanks!
The Javadoc says it all:
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.
One good way to ensure that close() is always called is by placing it inside a finally block:
Statement stmt = connection.createStatement();
try {
// use `stmt'
} finally {
stmt.close();
}
In Java 7, the above can be more concisely written as:
try (Statement stmt = connection.createStatement()) {
// ...
}
This is called the try-with-resources statement.
In general if you close a connection, all associated resources will be closed as well, provided the driver implementer did his work correctly. That said: it is better to close resources when your done with them, as that will free up resources both on your side and the database.
I am reviewing a big pile of existing code, trying to find unclosed connections that would cause the connection pool to run out or throw other erros.
In some places I see the connection is returned to the pool, the ResultSet is closed, but the PreparedStatement is not closed.
in pseudo code it would look like this:
Connection conn = null;
try {
conn = MyJdbcTemplateHolder.getNewConnectionFromPool();
PreparedStatement ps = conn.prepareStatement(sql, ...);
ResultSet rs = st.executeQuery();
// do stuff with results
} catch(Exception e) {
// exception
} finally {
rs.close();
MyJdbcTemplateHolder.returnConnectionToPool(conn);
//***** Here is what's missing: st.close(); *****
}
The question is: can the open statement cause issues because it wasn't explicitly closed? Or is closing the ResultSet and returning the connection enough?
Obviously I am not talking about one open statement - we have a pool of 100 connections and dozens of places in the code where this issue may come up.
MySQL version is 5.1
My JDBC jar is mysql-connector-java-5.1.11-bin.jar
The answer is yes, it can cause issues. As is discussed here in SO:
Closing JDBC Connections in Pool
JDBC MySql connection pooling practices to avoid exhausted connection pool
if you don't close connection-related resources in reverse order after you're done with them (or in a finally block), you're at risk. Connection pools vary on how they handle these, but it is worrisome - a minimum - that an improperly closed set of resources is thrown back into the pool.
In case it was unclear (and you may already know this), proper closing of resources is discussed further here:
How to properly clean up JDBC resources in Java?
Note that in forthcoming Java 7, there will be some help here:
http://www.javaspecialists.eu/archive/Issue190.html
in which a new try-with-resources statement is introduced in Java, which automatically closes any AutoCloseable resources referenced in the try statement.
I have a connection leak in some older Java web applications which do not utilize connection pooling.
Trying to find the leak is hard because IT will not grant me access to v$session SELECT Count(*) FROM v$session;
So instead I am trying to debug with System.out statements. Even after closing the connection conn.close(); when I print conn to the System log file it gives me the connection object name.
try {
Connection conn;
conn.close()
}
catch (SQLException e) { }
finally {
if (conn != null) {
try {
System.out.println("Closing the connection");
conn.close();
}
catch (Exception ex)
{
System.out.println("Exception is " + ex);
}
}
}
// I then check conn and it is not null and I can print the object name.
if (conn != null) {
System.out.println("Connection is still open and is " + conn);
}
however if I also add conn = null; below the conn.close(); statement the connection now seems closed. So my question is does conn.close(); actually release my connection or do I also have to make it null to really release my connection. Like I said it is really hard for me to determine if the connection is actually released without being able to query v$session. Is there snippet of java code which can give me my open connections??
It's probably educational at this point because I plan to refactor these applications to use connection pooling but I'm looking for a quick bandaid for now.
The important part of the close is what's happening on the database side. It's the RDBMS that has to close that connection. Calling the close() method is what communicates the message to the database to close the connection.
Setting the connection to null doesn't instruct RDBMS to do anything.
Same logic applies to ResultSet, which is a cursor on the database side, and Statement. You need to close those in individual try/catch blocks in the finally block of the method that created them, in reverse order of creation. Otherwise you'll see errors about "Max cursors exceeded".
Setting the conn to null only breaks the reference link to the connection object, and has no influence on the connection being open or not. If the connection is still open then the connection will still be referred to from inside the JDBC driver/connection pool etc...
Setting a variable to null is more telling the garbage collector that it is ok to clean up the original object when it wants to than anything else.
As others are saying, you've got two different concepts here: closing the connecting and tracking the connection in a variable.
To close the connection, call conn.close(). This will not set the variable conn to null. You can test if the connection is open with conn.isClosed().
If you don't care to track the connection in your code any more, you can conn = null. This does not immediately close the connection. I believe the connection will be automatically closed, based on the JDBC documentation :
Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be automatically released.
If you choose to go this route, be aware that the garbage collector may not close your connection as quickly as you want, and you may have what appears to be a resource leak; reserved database locks won't be released until the connection is garbage collected. Certain drivers (I don't know if oracle is one) impose maximum limit to the number of connections that may exist at one time, so leaving open connections can also cause failures to connect, later in the program.
Connection leaks are a best. I think a good strategy is to wrap the getting and releasing of connections in a couple of functions and then always get and release your connections through those functions. Then you can have those functions maintain a list of all open connections, and do a stack trace on the caller of the allocate function. Then have a screen that shows a list of all open connections and where they came from. Run this in a test environment, run around using a bunch of screens, then exit them all so all the connections SHOULD close, then bring up the screen that shows open connectoins, and the villain should be revealed.
My explanation here is an educated guess.
As a practice I have always set conn=null after the close. I believe when you do conn.close() you are telling the garbage collector that it's ready to be garbage collected. However, it will be up to the garbage collection process to determine when to do so.
Also you can change your
if(conn!=null)
to
if (conn.isClosed())
..
Is there snippet of Java code which can give me my open connections?
Statement smt = null;
ResultSet rs = null;
try {
// Create Statement from connection
smt = conn.createStatement();
// Execute Query in statement
rs = stmt.executeQuery("SELECT 1 FROM Dual");
if (rs.next()) {
return true; // connection is valid
}
catch (SQLException e) {
// Some sort of logging
return false;
}
finally {
if (smt != null) smt.close();
if (rs != null) rs.close();
}
Just a quick guess, assuming you are using Oracle.
Sugession: Why don't you install jboss and set up connection pooling through there?
I've been doing code review (mostly using tools like FindBugs) of one of our pet projects and FindBugs marked following code as erroneous (pseudocode):
Connection conn = dataSource.getConnection();
try{
PreparedStatement stmt = conn.prepareStatement();
//initialize the statement
stmt.execute();
ResultSet rs = stmt.getResultSet();
//get data
}finally{
conn.close();
}
The error was that this code might not release resources. I figured out that the ResultSet and Statement were not closed, so I closed them in finally:
finally{
try{
rs.close()
}catch(SqlException se){
//log it
}
try{
stmt.close();
}catch(SqlException se){
//log it
}
conn.close();
}
But I encountered the above pattern in many projects (from quite a few companies), and no one was closing ResultSets or Statements.
Did you have troubles with ResultSets and Statements not being closed when the Connection is closed?
I found only this and it refers to Oracle having problems with closing ResultSets when closing Connections (we use Oracle db, hence my corrections). java.sql.api says nothing in Connection.close() javadoc.
One problem with ONLY closing the connection and not the result set, is that if your connection management code is using connection pooling, the connection.close() would just put the connection back in the pool. Additionally, some database have a cursor resource on the server that will not be freed properly unless it is explicitly closed.
I've had problems with unclosed ResultSets in Oracle, even though the connection was closed. The error I got was
"ORA-01000: maximum open cursors exceeded"
So: Always close your ResultSet!
You should always close all JDBC resources explicitly. As Aaron and John already said, closing a connection will often only return it to a pool and not all JDBC drivers are implemented exact the same way.
Here is a utility method that can be used from a finally block:
public static void closeEverything(ResultSet rs, Statement stmt,
Connection con) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
}
}
}
Oracle will give you errors about open cursors in this case.
According to: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html
it looks like reusing a statement will close any open resultsets, and closing a statement will close any resultsets, but i don't see anything about closing a connection will close any of the resources it created.
All of those details are left to the JDBC driver provider.
Its always safest to close everything explicitly. We wrote a util class that wraps everything with try{ xxx } catch (Throwable {} so that you can just call Utils.close(rs) and Utils.close(stmt), etc without having to worry about exceptions that close scan supposedly throw.
The ODBC Bridge can produce a memory leak with some ODBC drivers.
If you use a good JDBC driver then you should does not have any problems with closing the connection. But there are 2 problems:
Does you know if you have a good driver?
Will you use other JDBC drivers in the future?
That the best practice is to close it all.
I work in a large J2EE web environment. We have several databases that may be connected to in a single request. We began getting logical deadlocks in some of our applications. The issue was that as follows:
User would request page
Server connects to DB 1
Server Selects on DB 1
Server "closes" connection to DB 1
Server connects to DB 2
Deadlocked!
This occurred for 2 reasons, we were experiencing far higher volume of traffic than normal and the J2EE Spec by default does not actually close your connection until the thread finishes execution. So, in the above example step 4 never actually closed the connection even though they were closed properly in finally .
To fix this, you you have to use resource references in the web.xml for your Database Connections and you have to set the res-sharing-scope to unsharable.
Example:
<resource-ref>
<description>My Database</description>
<res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
I've definitely seen problems with unclosed ResultSets, and what can it hurt to close them all the time, right? The unreliability of needing to remembering to do this is one of the best reasons to move to frameworks that manage these details for you. It might not be feasible in your development environment, but I've had great luck using Spring to manage JPA transactions. The messy details of opening connections, statements, result sets, and writing over-complicated try/catch/finally blocks (with try/catch blocks in the finally block!) to close them again just disappears, leaving you to actually get some work done. I'd highly recommend migrating to that kind of a solution.
In Java, Statements (not Resultsets) correlate to Cursors in Oracle. It is best to close the resources that you open as unexpected behavior can occur in regards to the JVM and system resources.
Additionally, some JDBC pooling frameworks pool Statements and Connections, so not closing them might not mark those objects as free in the pool, and cause performance issues in the framework.
In general, if there is a close() or destroy() method on an object, there's a reason to call it, and to ignore it is done so at your own peril.