java.sql.SQLException:结果集在sqlite上关闭

java.sql.SQLException:结果集在sqlite上关闭,java,sqlite,jdbc,sqlexception,Java,Sqlite,Jdbc,Sqlexception,我看了很多答案,但不幸的是没有一个答案能回答我的问题,我仍然不明白为什么我要关闭ResultSet 以下是导致问题的try代码片段: System.out.println(" System Info! @CHKMD5Files(): Found pre-existing details: "+TOTAL); Statement stmMD5 = null; Connection connMD5 = null; ResultSet

我看了很多答案,但不幸的是没有一个答案能回答我的问题,我仍然不明白为什么我要关闭
ResultSet

以下是导致问题的
try
代码片段:

        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();
        }
    }
System.out.println(“系统信息!@CHKMD5Files():找到预先存在的详细信息:“+TOTAL”);
语句stmMD5=null;
连接connMD5=null;
结果集rs_MD5=null;
字符串RESULTMD5=null;
试一试{
connMD5=DriverManager.getConnection(“jdbc:sqlite:+bkpPATH+hostname+.db”);
stmMD5=connMD5.createStatement();
connMD5.setAutoCommit(false);

而(ROWID当您想要使用
ResultSet
时,必须首先调用该方法,以在结果的第一行上设置
ResultSet
的指针。正如该方法的说明:

ResultSet游标最初位于第一行之前;对方法next的第一次调用使第一行成为当前行

因此,如果不调用它,就不会指向“无结果”,并且
getString
方法(在
RESULTMD5=rs_MD5.getString(“MD5”);
中使用)将生成该异常

rs_MD5.next()
在提取结果之前。
next
方法返回一个布尔值,指示它是否可以到达下一行。因此,您可能需要添加一个
if
-语句,在提取任何列值之前检查该值是否为真,因为如果
next
无法到达下一行(并返回false)它会将指针设置为无有效行(没有剩余行),如果您尝试访问结果,您将得到相同的错误(请参阅上面的链接至
next

但不幸的是,即使要添加对
next
的调用,在第二次迭代中也会出现相同的错误,因为不能使用相同的
语句
-对象来执行不同的查询。 每个
语句
-对象只能产生一个
结果集

要解决这个问题,您至少应该替换

但我建议您不要这样做,因为创建一个新的
语句
-对象非常耗时(每个对象在执行之前都必须编译)。由于在每次迭代中唯一更改的是
ROWID
,因此在每次迭代中重新编译相同的内容将是一种严重的时间浪费。因此请改用。它允许您使用只编译一次的语句,并且可以通过在语句中注入参数(编译后)重复使用多次。 要使用
PreparedStatement
,您应该执行以下操作:

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
// ...
注入这些参数的方法是使用
setXXX
方法,将“”的索引(基于1)作为第一个参数您要替换,第二个参数是值。
XXX
被替换为您要注入的值的类型。您只能注入有限类型的参数,因此在注入对象之前检查第一个参数。 您可以在中找到有关
PreparedStatement
的更多信息 或者(再举一些例子)

最后,我想补充一点,您应该关闭所有(JDBC)资源(
连接
语句
结果集
准备语句
,…)当您确定不再需要它们时。您不发布的资源是浪费的资源。您的JVM本可以分配给其他资源。不关闭您的资源是一个坏习惯,可能会导致性能下降


祝你好运!

如果你想使用
结果集
,你必须首先调用该方法,在结果的第一行设置
结果集
的指针。正如该方法的说明:

ResultSet游标最初位于第一行之前;对方法next的第一次调用使第一行成为当前行

因此,如果不调用它,就不会指向“无结果”,并且
getString
方法(在
RESULTMD5=rs_MD5.getString(“MD5”);
中使用)将生成该异常

rs_MD5.next()
在提取结果之前。
next
方法返回一个布尔值,指示它是否可以到达下一行。因此,您可能需要添加一个
if
-语句,在提取任何列值之前检查该值是否为真,因为如果
next
无法到达下一行(并返回false)它会将指针设置为无有效行(没有剩余行),如果您尝试访问结果,您将得到相同的错误(请参阅上面的链接至
next

但不幸的是,即使要添加对
next
的调用,在第二次迭代中也会出现相同的错误,因为不能使用相同的
语句
-对象来执行不同的查询。 每个
语句
-对象只能产生一个
结果集

要解决这个问题,您至少应该替换

但我建议您不要这样做,因为创建一个新的
语句
-对象非常耗时(每个对象在执行之前都必须编译)。由于在每次迭代中唯一更改的是
ROWID
,因此在每次迭代中重新编译相同的内容将是一种严重的时间浪费。因此请改用。它允许您使用只编译一次的语句,并且可以通过在语句中注入参数(编译后)重复使用多次。 要使用
PreparedStatement
,您应该执行以下操作:

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
// ...
注入这些参数的方法是使用
setXXX
方法,第一个参数是要替换的“?”的索引(基于1),第二个参数是值。
XXX
被值的类型替换
                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();
                }
            }