SQLException:结果集已关闭

Posted

技术标签:

【中文标题】SQLException:结果集已关闭【英文标题】:SQLException: the result set is closed 【发布时间】:2015-04-28 16:50:12 【问题描述】:

我是使用 NetBeans 的 Java 初学者,我正在尝试创建类似于教师注册系统的东西。我使用 SQL Server 2005 创建数据库。 在实施过程中,我试图创建一个函数,让学生能够注册他们的科目,因此该函数基本上搜索学生完成了先决条件的科目。于是我写了如下代码:

package GUIs;
import java.sql.*;
import javax.swing.*;


public class AddSubToStd extends javax.swing.JFrame 

final void FillList1()
    try
    String url = "jdbc:sqlserver://localhost:1433;databaseName=BIS";
    String username = "sa";
    String password = "*****";
    Connection conn  = DriverManager.getConnection(url,username,password);
    Statement stmt = conn.createStatement();
    DefaultListModel DLM = new DefaultListModel();
    ResultSet res = stmt.executeQuery("SELECT * FROM Students");
    while(res.next())
        DLM.addElement(res.getString("ID"));
    
    List1.setModel(DLM);

    catch(SQLException e)
        JOptionPane.showMessageDialog(null, e.toString());
    


final void FillList2()
    try
    String url = "jdbc:sqlserver://localhost:1433;databaseName=BIS";
    String username = "sa";
    String password = "*****";
    Connection conn  = DriverManager.getConnection(url,username,password);
    Statement stmt = conn.createStatement();
    DefaultListModel DLM = new DefaultListModel();
    String Query = "SELECT * FROM FinishedCourses WHERE ID = '"+List1.getSelectedValue()+"'";
    ResultSet res = stmt.executeQuery(Query);

    ResultSet res1;
    String S_Code;
    String Query1;

    while(res.next())

         S_Code = res.getString("S_Code");
         Query1 = "SELECT * From Subjects WHERE Prerequisite = '"+S_Code+"'";
         res1 = stmt.executeQuery(Query1);

        while(res1.next())

            DLM.addElement(res.getString("S_Code"));
        

    
    conn.close();
    stmt.close();
    List2.setModel(DLM);

    catch(SQLException e)
        JOptionPane.showMessageDialog(null, e.toString());
    


public AddSubToStd() 
    initComponents();
    FillList1();


但是当我尝试调用 FillList2() 时,我得到了 SQLException 表示结果集已关闭

 private void UpdateAllowedActionPerformed(java.awt.event.ActionEvent evt)                                               
    try
    String url = "jdbc:sqlserver://localhost:1433;databaseName=BIS";
    String username = "sa";
    String password = "*****";
    Connection conn  = DriverManager.getConnection(url,username,password);
    FillList2();    
    
    catch(SQLException e)
        JOptionPane.showMessageDialog(null, e.toString());
    

                                 

请有人帮忙。

【问题讨论】:

请将e.printStackTrace() 添加到您的catch 并将堆栈跟踪添加到您的问题中。 【参考方案1】:

您正在重复使用相同的 Statement 对象来执行两个查询。当stmt用于执行第二个查询时,前一条语句返回的ResultSet对象被关闭。为每个查询创建两个对象。

例子:

Statement stmt = conn.createStatement();
Statement stmt1 = conn.createStatement();
...
ResultSet res = stmt.executeQuery(Query);

...

while(res.next())

     S_Code = res.getString("S_Code");
     Query1 = "SELECT * From Subjects WHERE Prerequisite = '"+S_Code+"'";
     res1 = stmt1.executeQuery(Query1); // use a separate statement

    while(res1.next())

        DLM.addElement(res.getString("S_Code"));
    


Statement API docs 的以下引用对此进行了解释:

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

此外,强烈建议按照分配的相反顺序关闭 JDBC 资源,即您应该关闭 Statements 然后关闭 Connection,并且您应该这样做finally块:

catch(SQLException e)
    JOptionPane.showMessageDialog(null, e.toString());
 finally 
    if(res != null) 
        res.close();
    
    if(res1 != null) 
        res1.close();
    
    if(stmt != null) 
        stmt.close();
    
    if(stmt1 != null) 
        stmt1.close();
    
    if(conn != null) 
         conn.close();
    

如果您使用的是 Java 7,则可以使用 try-with-resources 语句自动关闭这些资源(无需显式调用 close() 方法):

// try-with-resources statement declaring two resources
try(Connection conn  = DriverManager.getConnection(url,username,password);
    Statement stmt = conn.createStatement()) 
    ...
 catch(SQLException e)
    JOptionPane.showMessageDialog(null, e.toString());

try-with-resources 将确保关闭 Statement 对象,然后在使用后关闭 Connection

【讨论】:

对于答案的最后一部分,最好使用 try-with-resource:它保证以正确的顺序关闭,即使发生异常(例如,如果在您的示例中抛出异常) finally 阻塞,那么连接可能不会关闭)。 建议使用PreparedStatement,这样OP 就不会因为'; DROP TABLE Students; -- 之类的课程代码遇到问题:) 感谢百万人。 try-with-resources 完美运行:D 顺便说一句,我不知道 PreparedStatement 是什么或如何使用它。我对这些东西还很陌生,所以我的知识为零。 Oracle's tutorial on PreparedStatements 提供了很好的概述。简而言之,您希望每次将变量传入 SQL 时都使用它们,以避免SQL injection 并使数据库能够重用您的查询。

以上是关于SQLException:结果集已关闭的主要内容,如果未能解决你的问题,请参考以下文章

oracle数据库java.sql.SQLException: 结果集已耗尽,总是跳不出while(rs.next())循环,请求高手帮忙解决!

java连接Oracle数据库,从ResultSet中提取数据出现java.sql.sqlException结果集已耗尽

Spring Boot 异步结果集已关闭

conn.rollback() 上的错误未处理 SQLException...如何正确使用 commit()?

Jsp--java.sqlsqlException结果集已耗尽

怎么关闭这些?一个结果报告