我是使用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()
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()); } }
有人请帮忙。
您正在重新使用同一Statement对象来执行两个查询。当stmt使用来执行第二个查询时,ResultSet前一条语句返回的 对象将关闭。为每个查询创建两个对象。
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块中这样做:
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()方法):
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它们。