Operation not allowed after ResultSet closed, mysql - java

Whenever I try and run this code I get: "java.sql.SQLException: Operation not allowed after ResultSet closed". It works without closing the connection but i'm curious as to why I get this error and what would be the correct way to close the connection, Here is the code:
public ResultSet UpdateTable(){
Connection con = connect();
ResultSet resultset;
Statement s = null;
resultset = null;
try{
s = con.createStatement();
resultset = s.executeQuery("select * from customera");
return resultset;
}
catch(SQLException e){
System.out.println(e.getMessage());
//con.close();
}
finally{
try{
s.close();
resultset.close();
con.close();
}
catch(SQLException e){
System.out.println(e.getMessage());
}
}
return null;
}
}

You would rather check whether they have any reference or not, then close them.
finally {
if (resultset != null) {
resultset.close();
}
if (s != null) {
s.close();
}
if (con != null) {
con.close();
}
}
I suspect, issue with
return resultset;
Since, you are closing the Connection and Statement before returning the ResultSet, so ResultSet might not be available. You must be aware finally block will execute before returning the value. That is also why, your code is working when you left your Connection open.
So, instead you should store the result into some data structure and return.

Your error is likely not coming from the code you show. Instead, it is being generated by other code, as a result of you closing your ResultSet and Statement before that other code uses it. (Closing the Statement also closes its ResultSet, according to the documentation.)
You can either call whatever code you need to finish using the ResultSet in this method, or you can just return the ResultSet and have it be the calling code's responsibility to close it. What you decide may depend on your other code, but I'd prefer making it be the calling code's responsibility (since it's specifically getting a ResultSet from this method, it should know it has to close it.)
As a side note, you should better differentiate your exception messages, so you can tell where they are coming from.

Related

Java ResultSet is not being closed properly

I have a Java application with many code snippets like the example below. Very simple querying of an Oracle database. Valid data is returned and parsed, then the close() functions are called.
ResultSet rs = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM example");
while (rs.next())
{
// do stuff
}
rs.close();
stmt.close();
System.out.println("test1");
}
catch (Exception e)
{
System.out.println("error1");
}
I started encountering a "maximum cursors exceeded" error. I checked my methods to determine whether ResultSets are not being closed. The catch clause was never triggered, and "test1" was printed every single time. Which means the rs.close() and stmt.close() lines are NOT being skipped. Yet the ResultSets are not actually being closed.
I added a finally clause and it cleared up the issue.
finally
{
if (rs != null)
{
try
{
rs.close();
System.out.println("test2");
}
catch (Exception e)
{
System.out.println("error2");
}
}
if (stmt != null)
{
try
{
stmt.close();
System.out.println("test3");
}
catch (Exception e)
{
System.out.println("error3");
}
}
}
OUTPUT:
test1
test2
test3
My question is, why do rs.close() and stmt.close() need to be called twice? The calls in the try clause appear to do nothing. Yet I call them again in the finally clause, and they are successful. How is this possible?
Use try-with-resources (Java 7+):
try (Statement stmt = conn.createStatement()) {
try (ResultSet rs = stmt.executeQuery("SELECT * FROM example")) {
while (rs.next()) {
// do stuff
}
System.out.println("test1");
}
} catch (Exception e) {
System.out.println("error1");
}
No, no need to call twice
No, there is no need in JDBC to be calling close twice. I suspect something else is going on.
We cannot tell for sure what is going on in your code with certainty. We cannot know if your supposedly second call actually fixed the problem. The documentation for Statement::close, for example, says:
Calling the method close on a Statement object that is already closed has no effect.
try-with-resources
As the Answer by Andreas suggests, you should be using a try-with-resources.
See:
Java 7 tech note on try-with-resources.
Oracle Tutorial.
Java 9 enhancement to try-with-resources, using previously-created variable within Try-With-Resource Statement.
Use try-with-resources for JDBC and also for any resource implementing AutoCloseable.
You can put one or more resources in your try( … ). Separate with semi-colons, the last semi-colon being optional. Java will take of tracking the resources, each being closed in the reverse order of being opened. If an exception occurs in the middle, Java knows not to try closing the null resource objects. This significantly simplifies your coding.

What's wrong with my code about Mysql and JAVA

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ConnectionDTB cdtb = new ConnectionDTB();
ResultSet rs = cdtb.retrieveData("select svcode from listSV");
if(!rs.isBeforeFirst()){
System.out.println("System is null");
//add
cdtb.close();
}
else{
while(rs.next()){
if(Integer.parseInt(jTextField1.getText()) == rs.getInt("svcode")){
System.out.println("ERROR");
cdtb.close();
break;
}
else{
if(rs.isLast()){
//add
cdtb.close();
}else{
cdtb.close();
}
}
My error is
Apr 25, 2015 2:21:29 AM GUI.Them1 jButton1ActionPerformed
SEVERE: null
java.sql.SQLException: Operation not allowed after ResultSet closed
What did I do wrong?
It looks like you are closing the database connection inside your loop, before you are done with the result set.
You can't close the database connection if you are still using statements or resultsets associated with the database connection. (Well, you can do it, but closing the connection will also close the resultset, and you get the kind of behavior you observe.)
The normative pattern is to use try/catch/finally blocks, and to close the resultset(s), statements(s) and connection in the finally block(s).
For example:
ConnectionDTB cdtb = null;
ResultSet rs = null;
try {
cdtb = new ConnectionDTB();
rs = cdtb.retrieveData("select svcode from listSV");
while(rs.next()){
// whatever processing you need to do on each row, but
// do NOT close the result set here
// do NOT close the database connection here!
}
} catch (SQLException ex) {
// anything you want to do if an exception is thrown
} finally {
if (rs != null) {
try { rs.close(); } catch (SQLException e) { /*ignore*/ }
}
if (cdtb != null) {
try { cdtb.close(); } catch (SQLException e) { /*ignore*/ }
}
}
That finally block could be simplified, removing the unnecessary try/catch. This would be fine too:
} finally {
if (rs != null) {
rs.close();
}
if (cdtb != null) {
cdtb.close();
}
}
The important thing here is to do the closing in the "finally" block, so that's going to be run even if an exception occurs. And with this pattern, there is one "close" of the database connection, it's not multiple calls scattered through your code.
Some other notes:
It looks as if your code means to "add" a row if one doesn't already exist. This is a lot of overhead, pulling back every value from the database and inspecting it.
It would be much more efficient to ask the database if such a row exists. To ask the database whether a row like that exists, use a statement like this:
SELECT svcode FROM listSV WHERE svcode = ?
Prepare the statement, bind a value to the placeholder (the value you are looking for), and execute the statement, and check if a row is returned or not.
If you are performing this check to see whether a row needs to be added to the listSV table, you could actually use a single INSERT ... SELECT statement to conditionally insert a row.
Although I don't think its actually shown from the information provided, I think that you are closing the result set (in this case 'rs') and then attempting to run an operation again.
If I had to guess as well, I'd say take out the rs.close because it is closing the result set prematurely. Maybe replace with a continue if you wanted to keep reading from the same set?
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ConnectionDTB cdtb = new ConnectionDTB();
ResultSet rs = cdtb.retrieveData("select svcode from listSV");
if(!rs.isBeforeFirst()){
System.out.println("System is null");
//add
cdtb.close();
rs.close();
}
else{
while(rs.next()){
if(Integer.parseInt(jTextField1.getText()) == rs.getInt("svcode")){
System.out.println("ERROR");
cdtb.close();
rs.close();
break;
}
else{
if(rs.isLast()){
//add
cdtb.close();
rs.close();
}
}
is this right?
by the way could u tell me AfterLast meaning?

refactor JDBC function

I am trying to create a simple web app that saves user data from a form to a database and reads the content of the database back to browser upon request. Following are the functions I have written so far.
connectToDB() // connects to database
addEmployee() // adds employee to database
displayEmployee() // returns a resultSet
isExisted(int staffID) // checks if the staff already exists
Database connection function:
public void connectToDB(){
try{
// load Apache derby driver
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
} catch(ClassNotFoundException e) {
System.err.println(e);
}
try{
connection = DriverManager.getConnection(DBNAME, USERNAME, PASSWORD);
} catch(SQLException e){
System.err.println(e);
}
} // end connectToDB
Display Employee function:
public ResultSet displayEmployee(){
connectToDB();
ResultSet result = null;
try{
Statement stmt = connection.createStatement();
String query = "SELECT * FROM APP.ADDRESSBOOK";
result = stmt.executeQuery(query);
} catch(SQLException e) {
System.err.println(e);
}
return result;
}
Check if employee exists:
public boolean isExisted(int StaffID){
connectToDB();
try{
Statement stmt = connection.createStatement();
String query = "SELECT StaffNum FROM APP.ADDRESSBOOK WHERE StaffNum = " + staff_number;
ResultSet result = stmt.executeQuery(query);
while(result.next()){
int temp = result.getInt(1);
if(temp == staff_number){return true;}
}
} catch(SQLException e) {
System.err.println(e);
}
return false;
}
As you can see, if you compare the displayEmployee() and isExisted(), I am repeating mysel. Both the function works but I am looking to refactor the code. In those function I havent closed the connection. If there were 20 functions in the web app that connects to the database my code would stink.
I am looking something like this:
* THIS CODE DOESNT WORK ******
private Statement queryDB(query){
connectToDB();
Statement stmt;
try{
stmt = connection.createStatement();
} catch(SQLException e) {
System.err.println(e);
}
return stmt;
// code for closing connection
}
public ResultSet DisplayEmployee(){
String query = "SELECT * FROM APP.ADDRESSBOOK";
Statement stmt = queryDB(query);
ResultSet result = stmt.executeQuery(query);
return result;
}
Thanks.
Using raw JDBC produces a lot of unsightly boilerplate code. One solution is to use Spring JDBC Template.
In addition you will get the sql exception hierarchy which will manage the underlying JDBC exceptions automatically as runtime exceptions.
For more see:
Introduction to Spring Framework JDBC
A couple of comments:
The catch statement of ClassNotFoundException should throw an exception and shouldn't continue further.
It is not a good idea to return resultsets from a method that obtained them upon statement execution, since it is the responsibility of that method to close it. Instead, you should either read out the results into objects or cache them into CachedRowSet if your downstream functions expect a resultset.
The connectToDB method should return a successful connection or throw exception.
You could write a method that takes in an SQL query and return the results as objects so that this method can be used for retrieving based on different criteria as long you are retrieving the objects of same type.
isExisted is using staff_number which I think you intend it to be staffID. If you found a row with this value, then there is no need to check if the result set contained the row with this value, right?
My two cents!

Proper way to return a ResultSet

I'm new to java but I'm picking it up pretty quickly. One thing that I keep running into is I end up having one function that is full of queries and just code in general and I would like to break it down into separate functions. Take this for example:
public ResultSet getApples (){
ResultSet rs;
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
rs = stmt.executeQuery();
} catch (SQLException e){
e.printStackTrace();
}
return rs;
}
Ideally this would be what I want to do, have all of try's and catches within one function, but this gives me the error: Local variable may not have been initilized
I do realize I could do this:
public function start(){
try{
ResultSet apples = getApples();
catch (SQLException e){
e.printStackTrace();
}
}
public ResultSet getApples () throws SQLException {
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
return stmt.executeQuery();
}
But I would really rather have the exceptions handled within the function as well as it return a result.
EDIT
Alright so kinda a modififed answer to whats being provided. My whole goal on this question was to make the main functions of my script as clean as possible. Even the extra if ( _resultSet != null ) was something that I didn't really like. That being said I am pretty happy with this result:
public ResultSet getApples (){
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
return stmt.executeQuery();
} catch (SQLException e){
System.out.println("************************");
System.out.println("Class.getApples null");
System.out.println(e.getMessage());
return null;
}
}
Everything is handled within the getApples function and when _resultSet.next() is called I get a NullPointerException and the prints in the getApples exception so I am able to find the error and debug quickly.
Initialize rs to null first.
public ResultSet getApples (){
ResultSet rs = null;
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
rs = stmt.executeQuery();
} catch (SQLException e){
e.printStackTrace();
}
return rs;
}
You can declare your RS like this
ResultSet rs = null;
but where you call your function:
ResultSet apples = getApples ()
you have to check:
if(apples == null)
{
//do something, because your query did not work.
}
Because you are not setting ResultSet rs to anything initial value. and at the end you are returning it.
What if any exception occurs and rs value does not have value set in it. In order to solve you need to assign null value to rs when you declare.
The biggest problem that I see with your first example (other than not initializing rs) is that you don't properly handle cleanup. You should have a finally block that closes stmt.
One very good way to make sure that all of this happens is to use Spring's JDBCTemplate (more documentation here). This handles all of the connection management details for you; you simply write your SQL and code to process the ResultSet. Better, it lets you use Spring's declarative transaction management.
You can use CachedRowSet. For detailed answer you can look at my answer here

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