java.sql.SQLException: ResultSet closed on sqlite

只愿长相守 提交于 2020-01-05 05:57:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!