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

Posted

技术标签:

【中文标题】结果集未打开,在一种情况下有效,另一种情况下无效【英文标题】: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);
           
    

【问题讨论】:

【参考方案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 被重置。

【讨论】:

同意,您可能想要创建一个用于插入的新语句。

以上是关于结果集未打开,在一种情况下有效,另一种情况下无效的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 在一种情况下而不是另一种情况下查看层次结构警告

为啥在一种情况下会收到带有字符串文字的不推荐使用的转换警告,而在另一种情况下却没有?

如何在一种情况下推送视图控制器,但在另一种情况下以模态方式呈现它?

MKNetworkEngine 不会触发它的方法

为啥 PHP 在一种情况下允许将文字传递给按引用传递的参数,而在其他情况下不允许?

角材料表:排序不起作用