Reading ResultSet: java.sql.SQLException: Operation not allowed after ResultSet closed - java

I'm trying to get information from a MySQL database. I can connect and do things such as insert data into tables fine, and although I receive a ResultSet, I can't read it. Here's my code:
public ResultSet executeQuery(String query) {
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
if (stmt.execute(query)) {
rs = stmt.getResultSet();
}
return rs;
}
catch (SQLException ex){
System.err.println("SQLException: " + ex.getMessage());
System.err.println("SQLState: " + ex.getSQLState());
System.err.println("VendorError: " + ex.getErrorCode());
}
finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) { } // ignore
stmt = null;
}
}
return null;
}
Trying to read the ResultSet:
ResultSet set = executeQuery("SELECT rank FROM players");
try {
while(set.next()) {
System.out.println(set.getInt("rank") + "");
}
} catch(Exception ex) {
ex.printStackTrace();
} finally {
try {
set.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
I get this error:
java.sql.SQLException: Operation not allowed after ResultSet closed
I've been looking around the internet and on different forums all day. What's wrong with my code?

Your finally block in executeQuery closes your statement before you've iterated over the results.

Well, two things -
1) I do not get why you have both execute() and executeQuery() in your method? I think executeQuery() should work for you.
2) Do not close the statement before iterating through resultset. Make it an instance variable and close it after iterating.

TL;DR Your executeQuery closes the Statement.
From the JavaDoc for Statement.close
Releases this Statement object's database and JDBC resources
immediately instead of waiting for this to happen when it is
automatically closed.
You close() your Statement before you read your ResultSet. Closing a Statement causes all of the ResultSet instances associate with that Statement to also be closed.
You need to pass in a Consumer<ResultSet> into a different method, and process the ResultSet whilst the Statement is open:
public void executeQuery(final String query, final Consumer<ResultSet> consumer) {
try(final Statement stmt = conn.createStatement();
final ResultSet rs = stmt.executeQuery(query)) {
consumer.accept(rs);
}
catch (SQLException ex){
System.err.println("SQLException: " + ex.getMessage());
System.err.println("SQLState: " + ex.getSQLState());
System.err.println("VendorError: " + ex.getErrorCode());
}
}
I have also fixed your code:
I have replaced your try..finally with a try-with-resources
You execute your query twice by calling stmt.executeQuery(query) and then stmt.execute(query). This is not only wasteful, but you lose the reference to the first ResultSet and if Statement.close didn't close all the associated resultsets you would have had a memory leak.

Related

SQLEXCEPTION Operation not allowed after ResultSet closed error insist

Hello i need to do 2 active jobs with database in java.Firstly I did with 1 statement but after I read hints in here they said that I should use 2 statement.But although it still get Operation not allowed after ResultSet closed error.
try{
Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e){
System.err.println("Driver yok");
return;
}
Connection con=null;
try{
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/kutuphane","root","");
System.out.println("Veritabnı baglandıldı");
Statement stmt=con.createStatement();
String strSQL="UPDATE emanetler SET IADETARIH='"+strdate+"' WHERE KISIAD='"+jTextField1.getText()+"' "
Statement stmt2=con.createStatement();
stmt.execute(strSQL);
ResultSet rs=stmt2.executeQuery("SELECT * FROM kitaplar");
while(rs.next()){
if(rs.getString("KITAPAD").equals(jTextField2.getText())){
strSQL="UPDATE kitaplar SET KITAPADET="+rs.getInt("KITAPADET")+"+1 WHERE KITAPAD='"+jTextField2.getText()+"' ";
stmt2.execute(strSQL);
}
}
stmt.close();
stmt2.close();
}
catch(SQLException e){
System.out.println("Veritabanı baglanmadi");
e.printStackTrace();
}
First you are using stmt2 object
ResultSet rs=stmt2.executeQuery("SELECT * FROM kitaplar");
Then in while loop
strSQL="UPDATE kitaplar SET KITAPADET="+rs.getInt("KITAPADET")+"+1 WHERE KITAPAD='"+jTextField2.getText()+"' ";
stmt2.execute(strSQL);
This must be corrected to use a separate Statement Object in While Loop to execute queries.
Hope this helps

Java prepared statement in try-with-resources not working [duplicate]

This question already has answers here:
How should I use try-with-resources with JDBC?
(5 answers)
Closed 8 years ago.
Yesterday multiple people on Stack recommended using try-with-resources. I am doing this for all my database operations now. Today I wanted to change Statement to PreparedStatement to make the queries more secure. But when I try to use a prepared statement in try-with-resources I keep getting errors like 'identifier expected' or ';' or ')'.
What am I doing wrong? Or isnt this possible? This is my code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()) {
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
A try-with-resource statement is used to declare (Autoclosable) resources. Connection, PreparedStatement and ResultSet are Autoclosable, so that's fine.
But stmt.setInt(1, user) is NOT a resource, but a simple statement. You cannot have simple statements (that are no resource declarations) within a try-with-resource statement!
Solution: Create multiple try-with-resource statements!
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
executeStatement(conn);
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
private void executeStatement(Connection con) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) {
stmt.setInt(1, user);
try (ResultSet rs = stmt.executeQuery()) {
// process result
}
}
}
(Please note that technically it is not required to put the execution of the SQL statement into a separate method as I did. It also works if both, opening the connection and creating the PreparedStatement are within the same try-with-resource statement. I just consider it good practice to separate connection management stuff from the rest of the code).
try this code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = pstmt.executeQuery())
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
note that here, resource is your Connection and you have to use it in the try block ()
Move
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()
...within the try{ /*HERE*/ }
This is because stmt is the resource being created try (/*HERE*/) {} to be used try{ /*HERE*/ }
Try-with-resources
try (/*Create resources in here such as conn and stmt*/)
{
//Use the resources created above such as stmt
}
The point being that everything created in the resource creation block implements AutoClosable and when the try block is exited, close() is called on them all.
In your code stmt.setInt(1, user); is not an AutoCloseable resource, hence the problem.

How to call Stored Procedure and prepared statement

In the below code I want to call one stored procedures and execute one Query. I am facing error at statement.executeUpdate(); Please help in fixing it. I am not sure where it going wrong.
public void Dbexe() {
Connection connection;
connection = DatabaseConnection.getCon();
CallableStatement stmt;
try {
stmt = connection.prepareCall("{CALL optg.Ld_SOpp}");
stmt.executeUpdate();
stmt.close();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Stored Procedure executed");
//PreparedStatement statement = null;
// ResultSet rs = null;
try{
PreparedStatement statement;
try {
statement = connection.prepareStatement("MERGE INTO OPTG.R_VAL AS TARGET USING" +
........... +
"");
statement.executeUpdate(); //Here the exception is thrown
statement.close();
connection.commit();
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// statement = connection.prepareStatement(query);
//statement.close();
}
finally{
System.out.println("Data is copied to the Table");
}
}
Little off-topic: You should use CallableStatement instead if you want to call a store procedure (see documentation):
CallableStatement callableStatement = connection.prepareCall("{call opptymgmt.Load_SiebelOpportunity}");
ResultSet rs = callableStatement.executeQuery();
I would also suggest you check this topic How to properly clean up JDBC resources in Java?. It was very helpful to me.
Update: based on this stack trace:
com.ibm.db2.jcc.am.mo: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=MERGE INTO OPPTYMGMT.REVENUE_VALIDAT;BEGIN-OF-STATEMENT;<variable_set>, DRIVER=4.7.85
The problem seems to be in the sql sentence you're trying to execute. I mean, is an error from DB2, not java. You should check your sql statement.
I got it working in this method:
PreparedStatement myStmt = conn.prepareStatement(sqlQuery);
myStmt.setInt(1, id); //position of parameter (1,2,3....) , value
ResultSet rs = myStmt.executeQuery();
while (rs.next()) {
int jobId = rs.getInt("jobId"); ....... }

resultset isn't going into while loop and set the value

Observing a strange behavior of this piece of code,because resultset is not giving the null value(doing SOP it's clear)but not going into while loop(that is quite strange!)and it's simple dao class,it's not able to set the value in user object:
public class DAO{
public List<User> searchAllUsers(int offset ,int noOfRecords, String column, String value){
String query="select SQL_CALC_FOUND_ROWS * from info where '"+column+"' like '%"+value+"%' order by serialNo asc limit " + offset + " , " + noOfRecords;
// String query="select * from info where '"+select+"' like '%"+search+"%' order by serialNo asc";
System.out.println("1");
List<User> list = new ArrayList<User>();
User user=null;
try {
System.out.println("b4 Connection");
connection = getConnection();
System.out.println("After Connection");
stmt = connection.createStatement();
System.out.println("Create statement");
ResultSet rs=stmt.executeQuery(query);
if(rs!=null)
System.out.println("1> Hi rs:"+rs);
while(rs!= null && rs.next()){
System.out.println("hi...!!");
user=new User();
user.setSerial(rs.getInt(1));
System.out.println("Serial : "+rs.getInt(1));
user.setName(rs.getString(2));
user.setEmail(rs.getString(3));
user.setImei(rs.getString(4));
System.out.println("I'm here !");
user.setModel(rs.getString(5));
user.setManufacturer(rs.getString(6));
user.setOsversion(rs.getString(7));
user.setHdyk(rs.getString(8));
user.setDate(rs.getString(9));
user.setAppname(rs.getString(10));
list.add(user);
System.out.println("Last..");
}
rs.close();
rs = stmt.executeQuery("SELECT FOUND_ROWS()");
System.out.println("2> :" +rs);
if(rs.next()){
this.noOfRecords = rs.getInt(1);
System.out.println("3> :" +this.noOfRecords);
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
finally
{
try {
if(stmt != null)
stmt.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
public int getNoOfRecords() {
return noOfRecords;
}
}
And it corresponding output is :
1
b4 Connection
After Connection
Create statement
1> Hi rs:com.mysql.jdbc.JDBC4ResultSet#35e6e3
2> :com.mysql.jdbc.JDBC4ResultSet#c9630a
3> :0
Even I'm also using the same code like it for select All user's and that point of time I'm getting proper o/p.
Spending so many hours for it,but unable to resolve it-where I'm going wrong....so your review & comment will be always welcome.
That's because your query didn't fetch you any row. And hence rs.next() will return false, hence the execution will not go into the while loop:
while(rs!= null && rs.next())
And you don't have to check for rs != null. It won't be null. The stmt.executeQuery always returns a ResultSet. Just have rs.next() in your while:
while(rs.next())
And yes, you should use PreparedStatement for executing your query rather than Statement. Here's a tutorial which will help you get started.

When do we need to call java.sql.Connection.rollback()?

I have to modify a few tables in one function. They must all succeed, or all fail. If one operation fails, I want them all to fail. I have the following:
public void foo() throws Exception {
Connection conn = null;
try {
conn = ...;
conn.setAutoCommit(false);
grok(conn);
conn.commit();
}
catch (Exception ex) {
// do I need to call conn.rollback() here?
}
finally {
if (conn != null) {
conn.close();
conn = null;
}
}
}
private void grok(Connection conn) throws Exception {
PreparedStatement stmt = null;
try {
// modify table "apple"
stmt = conn.prepareStatement(...);
stmt.executeUpdate();
stmt.close();
// modify table "orange"
stmt = conn.prepareStatement(...);
stmt.executeUpdate();
stmt.close();
...
}
finally {
if (stmt != null) {
stmt.close();
}
}
}
I'm wondering if I need to call rollback() in the case that something goes wrong during this process.
Other info: I'm using connection pooling. In the sample above, I'm also making sure to close each PreparedStatement using finally statements as well, just left out for brevity.
Thank you
Yes you need to call rollback if any of your statements fails or you have detected an exception prior to calling commit. This is an old post but the accepted answer is wrong. You can try it for yourself by throwing an exception before commit and observing that your inserts still make it into the database if you do not manually rollback.
JDBC Documentation
https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#call_rollback
Example Correct Usage from the doc
public void updateCoffeeSales(HashMap<String, Integer> salesForWeek)
throws SQLException {
PreparedStatement updateSales = null;
PreparedStatement updateTotal = null;
String updateString =
"update " + dbName + ".COFFEES " +
"set SALES = ? where COF_NAME = ?";
String updateStatement =
"update " + dbName + ".COFFEES " +
"set TOTAL = TOTAL + ? " +
"where COF_NAME = ?";
try {
con.setAutoCommit(false);
updateSales = con.prepareStatement(updateString);
updateTotal = con.prepareStatement(updateStatement);
for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) {
updateSales.setInt(1, e.getValue().intValue());
updateSales.setString(2, e.getKey());
updateSales.executeUpdate();
updateTotal.setInt(1, e.getValue().intValue());
updateTotal.setString(2, e.getKey());
updateTotal.executeUpdate();
con.commit();
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
if (con != null) {
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch(SQLException excep) {
JDBCTutorialUtilities.printSQLException(excep);
}
}
} finally {
if (updateSales != null) {
updateSales.close();
}
if (updateTotal != null) {
updateTotal.close();
}
con.setAutoCommit(true);
}
}
You don't need to call rollback(). If the connection closes without completing commit() it will be rolled back.
You don't need to set conn to null either; and since the try block starts after conn is initialized (assuming ... cannot evaluate to null) you don't need the != null in finally either.
If you call "commit" then the transaction will be committed. If you have multiple insert/update statements and one of them fails, committing will cause the inserts/updates that didn't fail to commit to the database. So yes, if you don't want the other statements to commit to the db, you need to call rollback. What you are essentially doing by setting autocommit to false is allowing multiple statements to be committed or rolledback together. Otherwise each individual statement will automatically commit.

Categories

Resources