Close ResultSet after using in catch-block - java

Eclipse IDE always shows following warning:
Resource leak: 'rset' is not closed at this location
But for me the code seems to be correct:
Statement stmt = null;
ResultSet rset = null;
try {
stmt = connection.createStatement();
try {
String query = foo();
rset = stmt.executeQuery(query);
} catch (Exception e) {
String query = bar();
rset = stmt.executeQuery(query);
}
return JsonHandler.resultSetToJson(rset);
} finally {
if (rset != null)
rset.close();
if (stmt != null)
stmt.close();
}
How do I close the ResultSet?

As commented, your second assignment of rset would let the first ResultSet object become a candidate for garbage collection without being closed. Thus the warning from the compiler or your IDE.
To more reliably and clearly close your resources, use try-with-resources.
try-with-resources syntax
Modern Java offers the try-with-resources syntax feature to automatically close any object that implements AutoCloseable with its single method close. The resources will be closed in the reverse of the order in which they were instantiated. And they are closed whether your code completes successfully or throws an exception.
See The Java Tutorials provided free of cost by Oracle Corp.
Try-with-resources is one of my favorite features in Java. Along with text blocks, database work is much easier now, and more fool-proof.
Connnection, Statement, and ResultSet are all such auto-closeable resources. So wrap them in try-with-resource syntax.
Exceptions
Get specific with your exceptions. Trap for the ones expected within the local context.
Code
Here is some untested code.
Notice how we name each ResultSet object differently.
Notice how the nesting of try-with-resources calls communicates visually the cascading structure of our logic.
try
(
Connection conn = myDataSource.getConnection() ;
Statement stmt = conn.createStatement() ;
)
{
try
(
ResultSet rsetFoo = stmt.executeQuery( foo() );
)
{
return JsonHandler.resultSetToJson( rsetFoo );
}
catch ( SQLException | SQLTimeoutException e)
{
try
(
ResultSet rsetBar = stmt.executeQuery( bar() );
)
{
return JsonHandler.resultSetToJson( rsetBar );
}
}
}
catch ( SQLException e )
{
…
}
catch ( SQLTimeoutException e )
{
…
}
If you had searched before posting, you would have found many existing examples, and much discussion, already posted on Stack Overflow.

Use try-with-resources feature
You can use try-with-resources feature of java 7 it will handle the auto closing of the resources as ResultSet,Statement implements AutoCloseable interface.
like : try (ResultSet rset = stmt.executeQuery(query))
similarly for other resources as well.

Try to put the returnstatement after the finally clause. i think your function is ignoring everything that comes after the return statement.
Try something like :
Statement stmt = null;
ResultSet rset = null;
String parsedResult = null; // String or the object type you want to return.
try {
stmt = connection.createStatement();
try {
String query = foo();
rset = stmt.executeQuery(query);
} catch (Exception e) {
String query = bar();
rset = stmt.executeQuery(query);
}
parsedResult = JsonHandler.resultSetToJson(rset);
} finally {
if (rset != null)
rset.close();
if (stmt != null)
stmt.close();
}
return parsedResult;

Related

Is it necessary to close PreparedStatement before preparing another Statement

Is it necessary to close ResultSet and PreparedStatement within one db.getConnection()? For the example below:
Connection conn = db.getConnection();
PreparedStatement pstmt = conn.prepareStatement(firstsql);
ResultSet r = pstmt.executeQuery();
// do something with the ResultSet
r.close();
pstmt.close(); // do I need close the r and pstmt here?
PreparedStatement pstmt = conn.prepareStatement(secondsql);
ResultSet r = pstmt.executeQuery();
// do something with the ResultSet again
r.close();
pstmt.close();
conn.close();
return null;
Are the codes of line 5 and line 6 necessary?
Strictly speaking, it is not necessary because you can have multiple prepared statements opened at the same time. What is necessary is to close every opened resource if it is not going to be utilised later.
Looking at your code, it doesn't ensure that the statement are, in fact, closed.
To ensure this, every close operation must be done inside a finally block: this way, it will executed whether the operation succeded or not.
Sample code:
PreparedStatement pstmt = null;
ResultSet r = null;
try {
pstmt = conn.prepareStatement(firstsql);
r = pstmt.executeQuery();
// do something with the ResultSet
} finally {
if (r != null) {
try {
r.close();
} catch (SQLException e) {
//log error
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
//log error
}
}
}
//and do it again
This code can be greatly simplified if you are using Java 7 with the try-with-resources statement:
try (PreparedStatement pstmt = conn.prepareStatement(firstsql);
ResultSet r = pstmt.executeQuery();) {
// do something with the ResultSet
}
No. You can have multiple statements open at the same time. But you must close them eventually.
The code you've posted doesn't compile, and if it did it would have a resource leak, but that's a different issue from the question in your title.

best practice to close jdbc resultset [duplicate]

This question already has answers here:
Where to close java PreparedStatements and ResultSets?
(13 answers)
Closed 8 years ago.
here is how I do it right now:
public static getConfs(Connection conn, String confNo){
ResultSet rs = null;
try{
rs = conn.createStatement().executeQuery("select col1,col2 from table1");
... // do something with rs
rs.getStatement().close();
rs = conn.createStatement().executeQuery("select col1,col2 from table2");
... // do somthing with rs
rs.getStatement().close();
rs = null;
}catch(Exception e){
throw e;
}finally{
if(rs != null){
try{
rs.getStatement().close();
}catch(SQLException se){
se.printStackTrace();
}
}
}
}
two questions:
1. should I reuse result set variable like that ?
2. is that good to close result set like that ? any smarter way?
Take a look at Spring JdbcUtils source, it closes ResultSet this way
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
logger.trace("Could not close JDBC ResultSet", ex);
} catch (Throwable ex) {
// We don't trust the JDBC driver: It might throw
// RuntimeException or Error.
logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
}
}
}
so your code would look like this
Statement st = conn.createStatement();
try {
ResultSet rs = st.executeQuery("select col1,col2 from table1");
// do something
closeResultSet(rs);
rs = st.executeQuery("select col1,col2 from table2");
// do something
closeResultSet(rs);
} finally {
// close Statement
}
Though in my opinion the best way not to work with JDBC at low level but use Spring JDBC directly. It thouroughly thought thru and will make your code simple and reliable.

Try / Try-with-resources and Connection, Statement and ResultSet closing

I have recently having some discussions with my professor about how to handle the basic jdbc connection scheme. Suppose we want to execute two queries, this is what he proposes
public void doQueries() throws MyException{
Connection con = null;
try {
con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
rs.close();
s2.close();
s1.close();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't really do anything
}
}
}
I don't like this approach, and I have two questions about it:
1.A) I think that, if any exception is thrown where we do 'other things', or in the line rs.close() or s2.close() then s1 wouldn't have been closed when the method ends. Am I right about that?
1.B) The professor keeps asking me to explicitly close the ResultSet (even when the Statement documentation makes clear that it will close the ResultSet) She says that Sun recommends it. Is there any reason to do so?
Now this is what I think is the correct code for the same thing:
public void doQueries() throws MyException{
Connection con = null;
PreparedStatement s1 = null;
PreparedStatement s2 = null;
try {
con = DriverManager.getConnection(dataSource);
s1 = con.prepareStatement(updateSqlQuery);
s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (s2 != null) {
s2.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (s1 != null) {
s1.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't do nothing
}
}
}
2.A) Is this code correct? (Is it guaranteed that all will be closed when the method ends?)
2.B) This is very large and verbose (and it gets worse if there are more Statements) Is there any shorter or more elegant way to do this without using try-with-resources?
Finally this is the code I like the most
public void doQueries() throws MyException{
try (Connection con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery))
{
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
}
}
3) Is this code correct? I think my professor doesn't like this way because there is no explicit close of the ResultSet, but she has told me that she is fine with it as long as in the documentation it is clear that all is closed. Can you give any link to the official documentation with a similar example, or based in the documentation show that there is are no problems with this code?
tl;dr
In theory closing the statement closes the result set.
In practice, some faulty JDBC driver implementations failed to do so, notoriously. Thus the advice from your instructor that she learned from the School Of Hard Knocks.
Unless you are familiar with every implementation of every JDBC
driver that might be deployed for your app, use
try-with-resources to auto-close every level of your JDBC
work such as statements and result sets.
Use try-with-resources syntax
None of your code is fully using try-with-resources. In try-with-resources syntax, you declare and instantiate your Connection, PreparedStatement, and ResultSet in parentheses, before the braces. See Tutorial by Oracle.
While your ResultSet is not being explicitly closed in your last code example, it should be closed indirectly when its statement is closed. But as discussed below, it might not be closed because of faulty JDBC driver.
AutoCloseable
Any such objects implementing AutoCloseable will automatically have their close method invoked. So no need for those finally clauses.
How do you know which objects are auto-closable and which are not? Look at their class documentation to see if it declares AutoCloseable as a super-interface. Conversely, see the JavaDoc page for AutoCloseable for a list of all the bundled sub-interfaces and implementing classes (dozens actually).
For example, for SQL work, we see that Connection, Statement, PreparedStatement, ResultSet, and RowSet are all auto-closable but DataSource is not. This makes sense, as DataSource stores data about potential resources (database connections) but is not itself a resource. A DataSource is never “open” so no need to close.
See Oracle Tutorial, The try-with-resources Statement.
Code example
Your last code example is getting close to good, but should have wrapped ResultSet in a try-with-resources statement to get automatically closed.
To quote ResultSet JavaDoc:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
As your teacher has been suggesting, there have been serious flaws in some JDBC drivers that failed to live up to the promise of the JDBC spec to close the ResultSet when its Statement or PreparedStatement is closed. So many programmers make a habit of closing each ResultSet object explicitly.
This extra duty is easier now with the try-with-resources syntax. In real work you’ll likely have a try-else around all your AutoCloseable objects such as ResultSet anyways. So my own opinion is: Why not make it a try-with-resources + else? Does not hurt, makes your code more self-documenting about your intentions, and it might help if your code ever encounters one of those faulty JDBC drivers. The only cost is a pair of parens, assuming you’d have a try-catch-else in place anyways.
As stated in the Oracle Tutorial, multiple AutoCloseable objects declared together will be closed in reverse order, just as we would want.
Tip: The try-with-resources syntax allows an optional semicolon on the last declared resource item. I include the semicolon as a habit because it reads well to my eye, is consistent, and facilitates cut-and-paste editing. I include it on your PreparedStatement s2 line.
public void doQueries() throws MyException{
// First try-with-resources.
try ( Connection con = DriverManager.getConnection( dataSource ) ;
PreparedStatement s1 = con.prepareStatement( updateSqlQuery ) ;
PreparedStatement s2 = con.prepareStatement( selectSqlQuery ) ;
) {
… Set parameters of PreparedStatements, etc.
s1.executeUpdate() ;
// Second try-with-resources, nested within first.
try (
ResultSet rs = s2.executeQuery() ;
) {
… process ResultSet
} catch ( SQLException e2 ) {
… handle exception related to ResultSet.
}
} catch ( SQLException e ) {
… handle exception related to Connection or PreparedStatements.
}
}
I suppose there is a more elegant syntax for this kind of work that might be invented in a future programming language. But for now, we have try-with-resources, and I do use it happily. While try-with-resources is not perfectly elegant, it is a big improvement over the older syntax.
By the way, Oracle recommends using a DataSource implementation for getting connections rather than the DriverManager approach seen in your code. Using DataSource throughout your code makes it easier to switch drivers or switch to a connection pool. See if your JDBC driver provides an implementation of DataSource.
Update: Java 9
Now in Java 9 you can initialize the resources before the try-with-resources. See this article. This flexibility may be useful in some scenarios.
The fun thing about JDBC code is that you're coding to a spec where it's not always clear how compliant your implementation is. There are a lot of different databases and drivers and some drivers are better-behaved than others. That tends to make people err on the side of caution, recommending things like closing everything explicitly. You could be ok with closing only the connection here. Closing the resultSet just to be on the safe side is hard to argue with. You don't indicate what database or driver you're using here, i wouldn't want to hardcode in assumptions about the driver that might not be valid for some implementation.
Closing things in sequence does leave you open to problems where an exception can get thrown and cause some of the closes to be skipped. You're right to be concerned about that.
Be aware this is a toy example. Most real code uses a connection pool, where calling the close method doesn't actually close the connection, instead it returns the connection to the pool. So resources may not get closed once you use a pool. If you want to change this code to use a connection pool then you'll have to go back and close the statements at least.
Also if you're objecting to the verbosity of this, the answer to that is to hide the code in reusable utilities that use strategies, resultSet mappers, prepared statement setters, etc. This has all been done before, of course; you'll be on the road to reinventing Spring JDBC.
Speaking of which: Spring JDBC closes everything explicitly (probably because it needs to work with as many drivers as possible, and doesn't want to cause problems due to some driver's not being well-behaved).
This is what I find to be the best solution for handling resources like JDBC. This method provides an immutable function, by leveraging final variables, and only declaring and assigning those variables if they are needed, it is very CPU efficient, and guarantees in all cases, that all resources that are assigned and opened are closed regardless of the state of exceptions. The technique you are using leaves gaps that can result in resource leaks if not carefully implemented to address all scenarios. This technique does not allow for a resource leak provided the pattern is always followed:
1) assign resource
2) try
3) use resource
4) finally close resource
public void doQueries() throws MyException {
try {
final Connection con = DriverManager.getConnection(dataSource);
try {
final PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
try {
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
} finally {
try { s1.close(); } catch (SQLException e) {}
}
final PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
try {
// Set the parameters of the PreparedStatements and maybe do other things
final ResultSet rs = s2.executeQuery();
try {
// Do something with rs
} finally {
try { rs.close(); } catch (SQLException e) {}
}
} finally {
try { s2.close(); } catch (SQLException e) {}
}
} finally {
try { con.close(); } catch (SQLException e) {}
}
} catch (SQLException e) {
throw new MyException(e);
}
}
With Java 7, you can leverage the new try -with-resources to simplify this even more: The new try -with-resources follows the above logic flow, in that it will guarantee all resources include in the with resources block that are assigned get closed. any exception thrown in the with resources block will the thrown, but those assigned resources will still be closed. This code is much simplified and looks like this:
public void doQueries() throws MyException {
try (
final Connection con = DriverManager.getConnection(dataSource);
final PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
final PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
final ResultSet rs = s2.executeQuery()) {
s1.executeUpdate();
// Do something with rs
} catch (SQLException e) {
throw new MyException(e);
}
}
[EDIT]: moved rs assignment into the resources block to show the simplest implementation. In practice, this simple solution does not really work, as this is not efficient. A connection should be reused, since establishing the connection is a very costly operation. Additionally, this simple example does not assign query parameters to the prepared statement. Care should be taken to handle these scenarios, as the the resource block should only include assignment statements. To depict this, I have also added another example
public void doQueries() throws MyException {
final String updateSqlQuery = "select ##servername";
final String selecSqlQuery = "select * from mytable where col1 = ? and col2 > ?";
final Object[] queryParams = {"somevalue", 1};
try (final Connection con = DriverManager.getConnection(dataSource);
final PreparedStatement s1 = newPreparedStatement(con, updateSqlQuery);
final PreparedStatement s2 = newPreparedStatement(con, selectSqlQuery, queryParams);
final ResultSet rs = s2.executeQuery()) {
s1.executeUpdate();
while (!rs.next()) {
// do something with the db record.
}
} catch (SQLException e) {
throw new MyException(e);
}
}
private static PreparedStatement newPreparedStatement(Connection con, String sql, Object... args) throws SQLException
{
final PreparedStatement stmt = con.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
stmt.setObject(i, args[i]);
return stmt;
}
This is indeed the primary motivation for try-with-resources. See the Java tutorials as reference. Your professor is out-of-date. If you want to deal with the result set issue you can always enclose it in another try-with-resources statement.
You could make a util class to handle closing of these resources. i.e
FYI i just ignored SQLExceptions from trying to close resources in the util class, but you could as verywell log or collect and throw them once you are done closing the resources in the collection depending on your needs
public class DBUtil {
public static void closeConnections(Connection ...connections){
if(connections != null ){
for(Connection conn : connections){
if(conn != null){
try {
conn.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
public static void closeResultSets(ResultSet ...resultSets){
if(resultSets != null ){
for(ResultSet rs: resultSets){
if(rs != null){
try {
rs.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
public static void closeStatements(Statement ...statements){
if(statements != null){
for(Statement statement : statements){
if(statement != null){
try {
statement.close();
} catch (SQLException ignored) {
//ignored
}
}
}
}
}
}
and then just call it from you method:
public void doQueries() throws MyException {
Connection con = null;
try {
con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = null;
PreparedStatement s2 = null;
try {
s1 = con.prepareStatement(updateSqlQuery);
s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = null;
try {
rs = s2.executeQuery();
} finally {
DBUtil.closeResultSets(rs);
}
} finally {
DBUtil.closeStatements(s2, s1);
}
} catch (SQLException e) {
throw new MyException(e);
} finally {
DBUtil.closeConnections(con);
}
}
I prefer to let Java auto-close. So I do something like this when I have to set values for ResultSet.
try (Connection conn = DB.getConn();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM x WHERE y = ?")
) {
ps.setString(1, "yValue");
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
...
}
}
} catch (SQLException e) {
e.printStackTrace(e);
...
}

PSQLException: this ResultSet is closed

i've occours this strange error for the first time in my life, and i don't know what does it means. I've a class that retrieve information from a table on a postgresql database, do some operations and return an arraylist with parsed element:
ResultSet rs = ProduttoreDCS.getProduttori();
System.out.println("Recuperato result set produttori");
ArrayList<String[]> res = new ArrayList<String[]>();
while (rs.next()) {
String[] current = new String[6];
current[0] = Integer.toString(rs.getInt("partita_iva"));
current[1] = rs.getString("nome");
current[2] = rs.getString("cognome");
current[3] = rs.getString("via_sede");
current[4] = rs.getString("citta_sede");
current[5] = rs.getString("provincia_sede");
res.add(current);
current = null;
}
return res;
the error is on "while" line.
public static ResultSet getProduttori() throws ClassNotFoundException, SQLException {
/*
* retrieve all record from produttori table
*/
Connection conn = null;
ResultSet res = null;
Statement stmt = null;
String query = "SELECT * FROM produttore";
conn = ConnectionManager.getConnection();
System.out.println("Connection obtained by ProduttoreDCS class");
stmt = conn.createStatement();
res = stmt.executeQuery(query);
stmt.close();
conn.close();
return res;
}
I've encountered the same problem by running the wrong combination of:
Postgres version;
Hibernate dialect;
postgres jdbc driver;
Updating all to the latest version solved the problem for me.
P.S. I know this is not what OP was asking, but this is the first result in Google when you search for the problem.
when you close the connection object in your getProduttori method, your result set will be automatically closed. when you try to re use it , it will be null.
ResultSet rs = ProduttoreDCS.getProduttori();
= null, as you have closed the connection in getProduttori
method, which will automatically close the resultset
thus, it returns null.
From Connection#close
Releases this Connection object's database and JDBC resources
immediately instead of waiting for them to be automatically released.
applies same when closing the Statement as well.For your code to work don't close Statement and Connection untill you get the rows.
#Baadshah has already shown you the standard way. If you are using java 7+ you can make use of try-with-resource block, which would make your life simpler.
try(Connection conn = gettheconn){
get the statement here
get the result set
perform your ops
}
catch(SQLException ex){
ex.printstacktrace();
}
If you observe, there is no finally block, your connection object will be closed once you exit the try block automatically.you don't have to explicity call Connection#close()
As per Docs
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
You are closed the connection and then you are iterating ,where it is null.Please read the data and then close the connection.
A good practice here is
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn =
stmt = conn.prepareStatement("sql");
rs = stmt.executeQuery();
//DO SOME THING HERE
} catch {
// Error Handling
} finally {
try { if (rs != null) rs.close(); } catch (Exception e) {};
try { if (stmt != null) stmt.close(); } catch (Exception e) {};
try { if (conn != null) conn.close(); } catch (Exception e) {};
}
This is the problem:
stmt.close();
conn.close();
You're closing the connection to the database. You can't do that until you've read the data - otherwise how is the ResultSet going to read it? Maybe it will have read some data in to start with, but it's not meant to be a disconnected object.
In particular, from the docuemntation for ResultSet.close:
Note: 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.
Closing the connection makes the resultSet go away.
A ResultSet is not a container you can use to pass data around in, it's only a wrapper around a cursor. You should run through the resultSet contents and copy them into a data structure, then return the data structure. You are already doing that, but you need to do it before closing the statement and connection.
Change the code to:
public static List<String[]> getProduttori() throws ClassNotFoundException, SQLException {
ArrayList<String[]> res = new ArrayList<String[]>();
/*
* retrieve all record from produttori table
*/
Connection conn = null;
ResultSet rs = null;
Statement stmt = null;
String query = "SELECT * FROM produttore";
conn = ConnectionManager.getConnection();
try {
System.out.println("Connection obtained by ProduttoreDCS class");
stmt = conn.createStatement();
try {
rs = stmt.executeQuery(query);
while (rs.next()) {
String[] current = new String[6];
current[0] = Integer.toString(rs.getInt("partita_iva"));
current[1] = rs.getString("nome");
current[2] = rs.getString("cognome");
current[3] = rs.getString("via_sede");
current[4] = rs.getString("citta_sede");
current[5] = rs.getString("provincia_sede");
res.add(current);
}
return res;
} finally {
try {
stmt.close();
} catch (SQLException e) {
log.error(e);
}
}
} finally {
try {
conn.close();
} catch (SQLException e) {
log.error(e);
}
}
}

How can I avoid ResultSet is closed exception in Java?

As soon as my code gets to my while(rs.next()) loop it produces the ResultSet is closed exception. What causes this exception and how can I correct for it?
EDIT: I notice in my code that I am nesting while(rs.next()) loop with another (rs2.next()), both result sets coming from the same DB, is this an issue?
Sounds like you executed another statement in the same connection before traversing the result set from the first statement. If you're nesting the processing of two result sets from the same database, you're doing something wrong. The combination of those sets should be done on the database side.
This could be caused by a number of reasons, including the driver you are using.
a) Some drivers do not allow nested statements. Depending if your driver supports JDBC 3.0 you should check the third parameter when creating the Statement object. For instance, I had the same problem with the JayBird driver to Firebird, but the code worked fine with the postgres driver. Then I added the third parameter to the createStatement method call and set it to ResultSet.HOLD_CURSORS_OVER_COMMIT, and the code started working fine for Firebird too.
static void testNestedRS() throws SQLException {
Connection con =null;
try {
// GET A CONNECTION
con = ConexionDesdeArchivo.obtenerConexion("examen-dest");
String sql1 = "select * from reportes_clasificacion";
Statement st1 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs1 = null;
try {
// EXECUTE THE FIRST QRY
rs1 = st1.executeQuery(sql1);
while (rs1.next()) {
// THIS LINE WILL BE PRINTED JUST ONCE ON
// SOME DRIVERS UNLESS YOU CREATE THE STATEMENT
// WITH 3 PARAMETERS USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
System.out.println("ST1 Row #: " + rs1.getRow());
String sql2 = "select * from reportes";
Statement st2 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// EXECUTE THE SECOND QRY. THIS CLOSES THE FIRST
// ResultSet ON SOME DRIVERS WITHOUT USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
st2.executeQuery(sql2);
st2.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs1.close();
st1.close();
}
} catch (SQLException e) {
} finally {
con.close();
}
}
b) There could be a bug in your code. Remember that you cannot reuse the Statement object, once you re-execute a query on the same statement object, all the opened resultsets associated with the statement are closed. Make sure you are not closing the statement.
Also, you can only have one result set open from each statement. So if you are iterating through two result sets at the same time, make sure they are executed on different statements. Opening a second result set on one statement will implicitly close the first.
http://java.sun.com/javase/6/docs/api/java/sql/Statement.html
The exception states that your result is closed. You should examine your code and look for all location where you issue a ResultSet.close() call. Also look for Statement.close() and Connection.close(). For sure, one of them gets called before rs.next() is called.
You may have closed either the Connection or Statement that made the ResultSet, which would lead to the ResultSet being closed as well.
Proper jdbc call should look something like:
try {
Connection conn;
Statement stmt;
ResultSet rs;
try {
conn = DriverManager.getConnection(myUrl,"","");
stmt = conn.createStatement();
rs = stmt.executeQuery(myQuery);
while ( rs.next() ) {
// process results
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
} finally {
// you should release your resources here
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
you can close connection (or statement) only after you get result from result set. Safest way is to do it in finally block. However close() could also throe SqlException, hence the other try-catch block.
I got same error everything was correct only i was using same statement interface object to execute and update the database.
After separating i.e. using different objects of statement interface for updating and executing query i resolved this error. i.e. do get rid from this do not use same statement object for both updating and executing the query.
Check whether you have declared the method where this code is executing as static. If it is static there may be some other thread resetting the ResultSet.
make sure you have closed all your statments and resultsets before running rs.next. Finaly guarantees this
public boolean flowExists( Integer idStatusPrevious, Integer idStatus, Connection connection ) {
LogUtil.logRequestMethod();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connection.prepareStatement( Constants.SCRIPT_SELECT_FIND_FLOW_STATUS_BY_STATUS );
ps.setInt( 1, idStatusPrevious );
ps.setInt( 2, idStatus );
rs = ps.executeQuery();
Long count = 0L;
if ( rs != null ) {
while ( rs.next() ) {
count = rs.getLong( 1 );
break;
}
}
LogUtil.logSuccessMethod();
return count > 0L;
} catch ( Exception e ) {
String errorMsg = String
.format( Constants.ERROR_FINALIZED_METHOD, ( e.getMessage() != null ? e.getMessage() : "" ) );
LogUtil.logError( errorMsg, e );
throw new FatalException( errorMsg );
} finally {
rs.close();
ps.close();
}
A ResultSetClosedException could be thrown for two reasons.
1.) You have opened another connection to the database without closing all other connections.
2.) Your ResultSet may be returning no values. So when you try to access data from the ResultSet java will throw a ResultSetClosedException.
It happens also when using a ResultSet without being in a #Transactional method.
ScrollableResults results = getScrollableResults("select e from MyEntity e");
while (results.next()) {
...
}
results.close();
if MyEntity has eager relationships with other entities. the second time results.next() is invoked the ResultSet is closed exception is raised.
so if you use ScrollableResults on entities with eager relationships make sure your method is run transactionally.
"result set is closed" happened to me when using tag <collection> in MyBatis nested (one-to-many) xml <select> statement
A Spring solution could be to have a (Java) Spring #Service layer, where class/methods calling MyBatis select-collection statements are annotated with
#Transactional(propagation = Propagation.REQUIRED)
annotations being:
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
this solution does not require to set the following datasource properties (i.e., in JBoss EAP standalone*.xml):
<xa-datasource-property name="downgradeHoldCursorsUnderXa">**true**\</xa-datasource-property>
<xa-datasource-property name="resultSetHoldability">**1**</xa-datasource-property>

Categories