问题
I looked at many answers but unfortunately none answers my question and I still can't figure this out why I'm getting ResultSet closed
.
Here is the try
code snippet that`s causing the issue:
System.out.println(" System Info! @CHKMD5Files(): Found pre-existing details: "+TOTAL);
Statement stmMD5 = null;
Connection connMD5 = null;
ResultSet rs_MD5 = null;
String RESULTMD5 = null;
try {
connMD5 = DriverManager.getConnection("jdbc:sqlite:" + bkpPATH+ hostname + ".db");
stmMD5 = connMD5.createStatement();
connMD5.setAutoCommit(false);
while (ROWID <= TOTAL) {
rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");
RESULTMD5 = rs_MD5.getString("MD5");
skipBuffer.write(RESULTMD5);
skipBuffer.newLine();
skipBuffer.flush();
ROWID++;
}
System.out.println(" System Info! @CHKMD5Files(): Done with try");
} catch (Exception ex) {
System.out.println(" System Error! @CHKMD5Files (2): " + ex);
System.exit(5);
} finally {
if (stmMD5 != null){
stmMD5.close();
System.out.println(" System Info! @CHKMD5Files (2): Closing Statement(stmMD5)");
}
if (connMD5 != null) {
connMD5.close();
System.out.println(" System Info! @CHKMD5Files (2): Closing Connection(connMD5)");
}
skipBuffer.close();
}
}
Looks like the while loop does not even run because if I put print statement in the loop returns nothing.
回答1:
When you want to use a ResultSet
, you have to call the next method first to set the pointer of the ResultSet
on the first row of the results. As the Javadoc of the method says:
A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; ...
So if you don't call it, you ain't pointing to no result and the getString
method (used in RESULTMD5 = rs_MD5.getString("MD5");
) will generate that exception. So add at least
rs_MD5.next()
before you extract the results. The next
method returns a boolean value to indicate if it could get to following row or not. So you might want to add an if
-statement to check if that value is true before extracting any column-value because if the next
failed getting to the next row (and returns false) it will set the pointer to no valid row(there are no left) and you'll get the same error if you try to access the results (see the link to javadoc of next
above).
But unfortunately even if you would add a call to next
, you will get the same error in the second iteration because you can't use the same Statement
-object to execute different queries.
Each Statement
-object can only result in one ResultSet
.
To solve this you should at least replace
rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");
with
rs_MD5 = connMD5.createStatement().executeQuery(
"SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';"
);
But I would suggest you otherwise because creating a new Statement
-object is quite time consuming (each one has to be compiled before getting executed). As the only thing that changes at each iteration is the ROWID
it would be a terrible waste of time to recompile the same thing again at each iteration. So use a PreparedStatement instead. It allows you to use a statement that gets compiles only once and that you can reuse multiple times by injecting parameters in it (after it compilated).
To use a PreparedStatement
you should do:
Connection conn = ... //Connection to your database
PreparedStatement ps = conn.preparedStatement("SELECT * FROM person WHERE name = ? AND age = ?");
//First search all persons with name "J.Baoby" and age = 5
ps.setString(1, "J.Baoby");
ps.setInt(2, 5);
ResultSet set1 = ps.executeQuery();
// Do something with it
// ....
//Now I need persons with name "Henry" and age = 25
ps.setString(1, "Henry");
ps.setInt(2, 25);
ResultSet set1 = ps.executeQuery();
// Do something with it
// ...
The way to inject those parameters is to use a setXXX
method with as first argument the index (1-based) of the "?" you want to replace and the second argument is the value. The XXX
is replaced by the type of the value you want to inject. There are only limited types of parameters you can inject so check the Java API first before injecting an object in it.
You can find more info about PreparedStatement
in the Java API
or on on this site (with some more examples).
As last I'd like to add that you should close all your (JDBC) ressources (Connection
, Statement
, ResultSet
, PreparedStatement
, ...) when you're sure you won't need them anymore. Ressources you don't release are wasted ressources your JVM could have allocated to something else. Not closing your ressources is a bad habit and could result in a performance penalty.
Good luck!
回答2:
Many Thanks for all your responses and for pointing me in the correct PATH I have managed to fix the issue and it was because the ROWID had no data at the start and that was causing me the issue.
The additional statement checking if it is empty resulved my issue:
while (ROWID <= TOTAL) {
rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");
if (!rs_MD5.next() ) {
System.out.println(" System Info! @CHKMD5Files(): No data in rowid: "+ROWID);
ROWID++;
} else {
RESULTMD5 = rs_MD5.getString("MD5");
skipBuffer.write(RESULTMD5);
skipBuffer.newLine();
skipBuffer.flush();
ROWID++;
rs_MD5.close();
}
}
来源:https://stackoverflow.com/questions/40913684/java-sql-sqlexception-resultset-closed-on-sqlite