W
Wojtek
Joe Seigh wrote :
In the following I left out all the try/catch/finally for brevity.
Note to new-comers. DO NOT use this pattern. It is flawed and you may
end up with many connections left open due to when the GC calls
finalize!
public class SQL
{
private Connection conn;
public SQL()
{
conn = Databasae.getConnection();
}
public Data getData()
{
Statement st;
ResultSet rs;
Data data = new Data();
st = conn.createStatement();
rs = st.executeQuery("select id,name from table");
while ( rs.next() )
{
// code to fill data
}
return data;
}
public viod finalize()
{
conn.close();
}
}
and to use this:
-------------------------------
SQL sql = new SQL();
Data data = sql.getData();
sql = null;
-------------------------------
So from my thinking:
- a connection is established in the constructor
- a method retrieves information
- when sql is set tu null, the only reference goes away.
- some time in the future the GC calls the finalize method.
In practice, the connection appeared to be closed before the "while (
rs.next() )" loop completed.
When I made the following change, the problem went away.
public class SQL
{
public Data getData()
{
Connection conn;
Statement st;
ResultSet rs;
Data data = new Data();
conn = Databasae.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select id,name from table");
while ( rs.next() )
{
// code to fill data
}
conn.close();
return data;
}
}
I went back and forth several times between the to ways, and the
results were consistent.
There was no problem with finalize. What happened is the Statement and
ResultSet objects reference the connection internally. You dropped the
reference to your enclosing object and it's finalizer closed the connection
while it was still being referenced and used by the ResultSet object.
You assumed that if your enclosing object wasn't being referenced, that
the objects contained in it were no longer being referenced.
In the following I left out all the try/catch/finally for brevity.
Note to new-comers. DO NOT use this pattern. It is flawed and you may
end up with many connections left open due to when the GC calls
finalize!
public class SQL
{
private Connection conn;
public SQL()
{
conn = Databasae.getConnection();
}
public Data getData()
{
Statement st;
ResultSet rs;
Data data = new Data();
st = conn.createStatement();
rs = st.executeQuery("select id,name from table");
while ( rs.next() )
{
// code to fill data
}
return data;
}
public viod finalize()
{
conn.close();
}
}
and to use this:
-------------------------------
SQL sql = new SQL();
Data data = sql.getData();
sql = null;
-------------------------------
So from my thinking:
- a connection is established in the constructor
- a method retrieves information
- when sql is set tu null, the only reference goes away.
- some time in the future the GC calls the finalize method.
In practice, the connection appeared to be closed before the "while (
rs.next() )" loop completed.
When I made the following change, the problem went away.
public class SQL
{
public Data getData()
{
Connection conn;
Statement st;
ResultSet rs;
Data data = new Data();
conn = Databasae.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select id,name from table");
while ( rs.next() )
{
// code to fill data
}
conn.close();
return data;
}
}
I went back and forth several times between the to ways, and the
results were consistent.