This question already has answers here:
JAVA ERROR : package com.sun.rowset is not visible : com.sun.rowset is declared in module java.sql.rowset, which does not export it
(3 answers)
Closed last month.
When migrating my project to Java 19, I am getting this error related to our use of RowSet:
cannot access class com.sun.rowset.CachedRowSetImpl (in module java.sql.rowset) because module java.sql.rowset does not export com.sun.rowset to module
and this is my code
import javax.sql.rowset.*;
import com.sun.rowset.CachedRowSetImpl;
import java.sql.*;
import javax.sql.rowset.CachedRowSet;
public static ResultSet dbExecuteQuery(String queryStmt) throws SQLException, ClassNotFoundException {
//Declare statement, resultSet and CachedResultSet as null
Statement stmt = null;
ResultSet resultSet = null;
CachedRowSetImpl crs = null;
try {
//Connect to DB (Establish Oracle Connection)
dbConnect();
System.out.println("Select statement: " + queryStmt + "\n");
//Create statement
stmt = conn.createStatement();
//Execute select (query) operation
resultSet = stmt.executeQuery(queryStmt);
//CachedRowSet Implementation
//In order to prevent "java.sql.SQLRecoverableException: Closed Connection: next" error
//We are using CachedRowSet
crs = new CachedRowSetImpl();
crs.populate(resultSet);
} catch (SQLException e) {
System.out.println("Problem occurred at executeQuery operation : " + e);
throw e;
} finally {
if (resultSet != null) {
//Close resultSet
resultSet.close();
}
if (stmt != null) {
//Close Statement
stmt.close();
}
//Close connection
dbDisconnect();
}
//Return CachedRowSet
return crs;
}
I try because I don't know how to solve my problem and i expect that this problem will be solve
com.sun.rowset.CachedRowSetImpl is a JDBC implementation detail. By historic convention all the classes under com.sun package are considered implementation detail. The distinction between JDK implementation detail and interface was enforced with the introduction of Java 9 module system.
In short you don't want to write your code depending on the JDK implementation details as they can change without warning.
See How to Use CachedRowSet in JDBC, section 3. Creating a CachedRowSet Object, which shows how to create the same object using RowSetProvider and a CachedRowSet interface:
RowSetFactory rsf = RowSetProvider.newFactory();
CachedRowSet crs = rsf.createCachedRowSet();
Related
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;
This question already has answers here:
mysql prepared statement error: MySQLSyntaxErrorException
(2 answers)
Closed 6 years ago.
I've a course table with the columns,
id, teacher_id and name.
This is the method that I'm using to get a course by id.
public static Course getById(int id) throws SQLException {
String query = "SELECT * FROM courses WHERE id = ?" ;
Course course = new Course();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try{
DriverManager.registerDriver(new com.mysql.jdbc.Driver ());
connection = (Connection) DriverManager.getConnection(ConnectDb.CONN_STRING, ConnectDb.USERNAME, ConnectDb.PASSWORD);
statement = (PreparedStatement) connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
statement.setInt(1, id);
resultSet = statement.executeQuery(query);
while (resultSet.next()) {
course.setId(resultSet.getInt("id"));
course.setName(resultSet.getString("name"));
course.setTeacherId(resultSet.getInt("teacher_id"));
}
}catch (SQLException e) {
System.err.println(e);
}finally{
if (resultSet != null) resultSet.close();;
if (statement != null) statement.close();
if(connection != null) connection.close();
}
return course;
}// end of method
When I run this method, I get an output id :0, teacher_id : 0
The server log says that I've an SQLException
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1
The bug is here:
resultSet = statement.executeQuery(query);
You're not calling PreparedStatement#executeQuery, you're calling Statement#executeQuery (Statement is a superinterface of PreparedStatement). So the parameter substitution isn't happening and you're actually sending that ? to the server.
Change it to:
resultSet = statement.executeQuery();
// No argument here ---------------^
(And yes, this is an API design flaw; and no, you're not the first to fall into it.)
There are a few other things about that code that could use improvement:
You're always returning a Course, even if an exception occurred. Best practices would be to allow the exception to propagate to the caller; second-best practices would be to return some kind of flag to the caller that an error occurred, such as null.
The try-with-resources statement can make that code both shorter and clearer
You shouldn't have to cast the return values of getConnection or prepareStatement.
You're using while, but you're expecting only a single result. if would make more sense.
On that topic, you can give the driver a hint in that regard by using setMaxRows.
Your method declares that it can throw SQLException, which is literally true since it calls close, but the only useful SQLException is actually being caught, logged, and suppressed by the code, making declaring it on the method a bit misleading.
I'm told modern JDBC drivers don't need the registerDriver call anymore. (I personally haven't used JDBC for a while now, so...)
Here's an example incoporating the above. It allows an exception to propagate, so errors (exceptional conditions) are not handled in the normal flow of code; it returns null if there's no matching course:
public static Course getById(int id) throws SQLException {
String query = "SELECT * FROM courses WHERE id = ?";
try (
Connection connection = DriverManager.getConnection(ConnectDb.CONN_STRING, ConnectDb.USERNAME, ConnectDb.PASSWORD);
PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
) {
statement.setInt(1, id);
statement.setMaxRows(1);
try (
ResultSet resultSet = statement.executeQuery();
) {
if (resultSet.next()) {
Course course = new Course();
course.setId(resultSet.getInt("id"));
course.setName(resultSet.getString("name"));
course.setTeacherId(resultSet.getInt("teacher_id"));
return course;
}
// No matching course
return null;
}
}
} // end of method
That can probably be improved further, but you get the idea.
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);
...
}
I am practicing JDBC batch processing and having errors:
error 1: Unsupported feature
error 2: Execute cannot be empty or null
Property files include:
itemsdao.updateBookName = Update Books set bookname = ? where books.id = ?
itemsdao.updateAuthorName = Update books set authorname = ? where books.id = ?
I know I can execute about DML statements in one update, but I am practicing batch processing in JDBC.
Below is my method
public void update(Item item) {
String query = null;
try {
connection = DbConnector.getConnection();
property = SqlPropertiesLoader.getProperties("dml.properties");
connection.setAutoCommit(false);
if ( property == null )
{
Logging.log.debug("dml.properties does not exist. Check property loader or file name is spelled right");
return;
}
query = property.getProperty("itemsdao.updateBookName");
statement = connection.prepareStatement(query);
statement.setString(1, item.getBookName());
statement.setInt(2, item.getId());
statement.addBatch(query);
query = property.getProperty("itemsdao.updateAuthorName");
statement = connection.prepareStatement(query);
statement.setString(1, item.getAuthorName());
statement.setInt(2, item.getId());
statement.addBatch(query);
statement.executeBatch();
connection.commit();
}catch (ClassNotFoundException e) {
Logging.log.error("Connection class does not exist", e);
}
catch (SQLException e) {
Logging.log.error("Violating PK constraint",e);
}
//helper class th
finally {
DbUtil.close(connection);
DbUtil.closePreparedStatement(statement);
}
You are mixing together methods of Statement and PreparedStatement classes:
(addBatch(String sql) belongs to Statement and cannot be called on a PreparedStatement or CallableStatement
addBatch() is to be used with PreparedStatement (as your tutorial shows).
Oracle implements both it's own and standard (JDBC 2.0) batch processing. From the Standard Update Batching docs:
In Oracle JDBC applications, update batching is intended for use with
prepared statements that are being processed repeatedly with different
sets of bind values.
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>