Closing Oracle cursors from JDBC

We have a class DB for connecting to an Oracle database with the following method:

public ResultSet execQuery(String sqlQryStr)throws SQLException{

Statement stmt =null ;

ResultSet rs =null ;

try{

stmt = theConn.createStatement ();

rs = stmt.executeQuery(sqlQryStr);

}catch (Exception e){

thrownew SQLException ( e.toString() ) ;

}

return rs ;

}

Hey I didn抰 write this, be nice.. As you can imagine this leave open cursors, consuming 30 an hour. Quick fix was perform a getDBConnection() and create the Statement and ResultSet local and run the query from there, cleaning up in thefinally

. So much for encapsulation; but for a quick fix it is doing the job.

I thought maybe declaring a Global Statement and ResultSet in the DB.java. But then I抦 limited to 1 query at a time, no good.

Since I have returned the ResultSet I thought maybe in the localised code,

try{

rs.close();

}catch (SQLException e){

logger.warn("Error closing ResultSet: " + e.toString()) ;

}

try{

rs.getStatement().close();

}catch (SQLException e){

logger.warn("Error closing Statement: " + e.toString()) ;

}

This also seems a bit messy? But maybe it is the correct way of achieving this.

What is considered a neat Object Oriented approach to this problem?

Thanks in advance for any replies.

[2333 byte] By [QldKeva] at [2007-9-24]
# 1
Thinking about it thers.getStatement().close();would have a problem as I closed the ResultSet first... If you close the Statement does that auto close the ResultSet?If not I will have to save the Statement to a local var, and close if last.
QldKeva at 2007-7-14 > top of java,Database Connectivity,Java Database Connectivity (JDBC)...
# 2

The execQuery() also has a problem: if executeQuery() throws an exception, the statement remains unclosed. Most attempts to wrap SQL execution have some way they leak something when an error occurs.

I'd just not try to create an execQuery() wrapper. It saves, what, one or two lines of typing. Just do like so:

void whatever()

{

Connection connection = null;

PreparedStatement stmt = null;

ResultSet res = null;

try {

String sql = "select ...";

connection = pool.getConnection(); // or however your connection pool works

stmt = connection.prepareStatement(sql);

res = stmt.executeQuery();

while (res.next()) {

...;

}

} finally {

// Close in reverse order of creation

SqlUtil.close(res);

SqlUtil.close(stmt);

SqlUtil.close(connection);

}

}

public class SqlUtil

{

public static void close(Statement stmt)

{

if (stmt == null) // can be null if an exception occurred

return;

try {

stmt.close();

} catch (Exception e) {

log.error(e, "error closing database statement");

}

}

// ditto for ResultSet and Connection

/* You could also write a close(ResultSet, Statement, Connection).

* That has the advantage that it can close all three, and then throw an SqlException

* if any of the closes failed. Three separate closes can log the exception

* but can't easily pass it upwards.

*/

}

sjasjaa at 2007-7-14 > top of java,Database Connectivity,Java Database Connectivity (JDBC)...
# 3
Thanks for the feedback. I think your way keeping it in the main will be the easiest and cleanest to read.
QldKeva at 2007-7-14 > top of java,Database Connectivity,Java Database Connectivity (JDBC)...