It seems that the ResultSet
will be automatically closed when I close the Connection
.
But I want to return the ResultSet
and use it in another method, then I don't know where to close Connection
and PreparedStatement
.
public ResultSet executeQuery(String sql, String[] getValue)
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
conn = getConn();
pstmt = conn.prepareStatement(sql);
if (getValue != null)
{
for (int i = 0; i < getValue.length; i++)
{
pstmt.setString(i + 1, getValue[i]);
}
}
rs = pstmt.executeQuery();
} catch (Exception e)
{
e.printStackTrace();
closeAll(conn, pstmt, rs);
}
return rs;
}
I've moved closeAll(conn, pstmt, null);
into catch block because I found that if I put it in finally block I'll lost my rs
immediately just before it returns.
Now when I want to close the rs
, I can't close the conn
and pstmt
. Is there any solution?
Use
CachedRowSet
for holding info after disconnectingOne clean way of coding this is to pass in an object that has a callback method that takes a result set.
Your other method creates the object with the callback method with it's resultSet handling code, and passes that to the method that executes the SQL.
That way, your SQL & DB code stays where it belongs, your result set handling logic is closer to where you use the data, and your SQL code cleans up when it should.
The way you have it right now, the connection would never close which would cause problems later (if not immediately) for your program and the RDBMS. It would be better to create a Java class to hold the fields from the ResultSet and return that. The ResultSet is linked to the connection, so returning it and closing the connection is not possible.
You should never pass
ResultSet
(orStatement
orConnection
) into the public outside the method block where they are to be acquired and closed to avoid resource leaks. A common practice is just to map theResultSet
to aList<Data>
whereData
is just a javabean object representing the data of interest.Here's a basic example:
and here's a basic example of how to handle it correctly:
you can use it as follows:
To learn more about the best practices with JDBC you may find this basic kickoff article useful as well.
Actually, you've almost answered that question yourself. As you experimented, closing the
Connection
will release the JDBC resources associated to it (at least, this is how things should work). So, if you want to return aResultSet
(I'll come back on this later), you need to close the connection "later". One way to do this would be obviously to pass a connection to your method, something like this:The problem is that I don't really know what is your final goal and why you need so low level stuff so I'm not sure this is a good advice. Unless if you are writing a low level JDBC framework (and please, don't tell me you are not doing this), I would actually not recommend returning a
ResultSet
. For example, if you want to feed some business class, return some JDBC-independent object or a collection of them as other have advised instead of aResultSet
. Also bear in mind that aRowSet
is aResultSet
so if you should not use aResultSet
then you should not use aRowSet
.Personally, I think you should use some helper class instead of reinventing the wheel. While Spring may be overkill and has a bit of learning curve (too much if you don't know it at all), Spring is not the only way to go and I strongly suggest to look at Commons DbUtils. More specifically, look at
QueryRunner
and especially thisquery()
method:As you can see, this method allows to pass a
ResultSetHandler
which exposes a callback method to convertResultSets
into other objects as described in z5h's answer and DbUtils provides several implementations, just pick up the one that will suit your needs. Also have a look at the utility methods of theDbUtils
class, for example the variousDbUnit.close()
that you may find handy to close JDBC resources.Really, unless you have very good reasons to do so (and I'd be curious to know them), don't write yet another JDBC framework, use an existing solution, it will save you some pain and, more important, some bugs and you'll benefit from proven good design. Even for low level stuff, there are existing (and simple) solutions as we saw. At least, check it out.
You can call
ResultSet.getStatement
to retrieve theStatement
, andStatement.getConnection
to retrieve theConnection
.From these you can write a
closeResultSet
utility method that will close all 3 for you, given nothing but theResultSet
.