【问题标题】:resultSet not open, works in one case another case not结果集未打开,在一种情况下有效,另一种情况下无效
【发布时间】:2015-07-31 22:14:50
【问题描述】:

为什么如果我使用 queryFromDb() 从 db 类查询数据库,当它第二次尝试执行 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);
        }   
    }
}

【问题讨论】:

    标签: java sql jdbc derby resultset


    【解决方案1】:

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

    默认情况下,每个 Statement 对象只能同时打开一个 ResultSet 对象。因此,如果一个 ResultSet 对象的读取与另一个 ResultSet 对象的读取交错,则每个对象都必须由不同的 Statement 对象生成。 Statement 接口中的所有执行方法都会隐式关闭一个语句的当前 ResultSet 对象,如果存在打开的对象。

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

    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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 同意,您可能想要创建一个用于插入的新语句。
      猜你喜欢
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多