结果集未打开,在一种情况下有效,另一种情况下无效

resultSet not open, works in one case another case not

为什么如果我使用 queryFromDb() 从数据库 class 查询数据库,当它第二次尝试执行 rs.next() 时我得到 "ResultSet not open" 而如果我尝试使用 queryFromMain 一切正常吗?

public class Db {

private String protocol = "jdbc:derby:";
private ResultSet resultSet = null;
private Connection connection = null;
private Statement statement;

public Db(){

    try{
        Properties props = new Properties(); 
        props.put("user", "user");
        props.put("password", "password");

        String dbName = "database";
        connection = DriverManager.getConnection(protocol + dbName  , props);

    }
    catch(SQLException sqle){
        printSQLException(sqle);
    }
}

public ResultSet returnValue(String query){

    try{
        statement = connection.createStatement();

        resultSet = statement.executeQuery(query);  
    }
    catch(SQLException sqle){
        printSQLException(sqle);
    }

    return resultSet;   
}


public void queryFromDb(){
         try {
            statement = connection.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM clsbck ORDER BY id");  
            while(rs.next()){
                System.out.println(rs.getString(2));
                String str = "INSERT INTO cls rck VALUES 2";
                [...]           
                statement.execute(str); 
            }
         } catch (SQLException e) {
            printSQLException(e);
         }  
    }

   }
}

public class Main {
    private static Db db;

    public static void main(String[] args){
        db = new Db();
    }

    public static void queryFromMain(){
        ResultSet rs = db.returnValue("SELECT * FROM clsbck ORDER BY id");
        try {   
           while(rs.next()){
               String str = "INSERT INTO cls rck VALUES 2";     
               [...]
               db.addValue(str);
           }
        } catch (SQLException e) {
            printSQLException(e);
        }   
    }
}

可能是因为您在 while 循环记录集中重用对象 statement 被重置。

每个 Statement 你应该只打开一个 ResultSet;在 queryFromDb 中,您将在 statement.executeQuery 中打开一个,并(隐含地)在 statement.execute(str) 中的循环中打开另一个。来自 documentation:

By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.

您可以通过执行以下操作来修复此方法:

public void queryFromDb() {

    Statement queryStatement = null;
    PreparedStatement insertStatement = null;

    try {
        queryStatement = connection.createStatement();
        insertStatement = connection.prepareStatement(
                             "INSERT INTO cls rck VALUES 2");

        ResultSet rs = queryStatement
                .executeQuery("SELECT * FROM clsbck ORDER BY id");

        while (rs.next()) {
            System.out.println(rs.getString(2));
            // [...]
            insertStatement.executeUpdate();
        }
        rs.close();
    } catch (SQLException e) {
        printSQLException(e);
    } finally {
        if (queryStatement != null) {
            queryStatement.close();
        }
        if (insertStatement != null) {
            insertStatement.close();
        }
    }
}

您不应该在代码中使用全局(方法范围)Statement 对象;相反,在本地声明它们。对于循环内发生的SQL INSERT,应该使用一个PreparedStatement,它在循环外准备并在循环内执行(将查询中的值替换为绑定占位符( ?) 如果您想更改每次迭代时插入的值)。

最后,记得在使用后关闭资源(ResultSets 和 Statements)。如果您使用 Java 7 或更高版本,最流畅的方法是使用 try-with-resources statement.