小编典典

SQLException:结果集已关闭

sql

我是使用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();

}

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

 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());
    }

}

有人请帮忙。


阅读 335

收藏
2021-03-17

共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"));
    }

}

以下是来自StatementAPI文档的引文中对此的解释:

默认情况下,ResultSet每个Statement对象只能同时打开一个对象。因此,如果一个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它们。

2021-03-17