2009-06-01 2 views
21

Sobald mein Code an meine while(rs.next()) Schleife gelangt, erzeugt er die ResultSet ist geschlossene Ausnahme. Was verursacht diese Ausnahme und wie kann ich sie korrigieren?Wie kann ich vermeiden, dass ResultSet eine geschlossene Ausnahme in Java ist?

EDIT: ich in meinem Code feststellen, dass ich nisten while(rs.next()) Schleife mit einem anderen (rs2.next()), beide Ergebnismengen aus dem gleichen DB kommt, ist das ein Problem?

+5

Fügen Sie eine Auflistung Ihres Codes hinzu. – JeeBee

Antwort

39

Klingt so, als ob Sie eine weitere Anweisung in derselben Verbindung ausgeführt haben, bevor Sie die Ergebnismenge der ersten Anweisung durchlaufen haben. Wenn Sie die Verarbeitung von zwei Resultsets aus derselben Datenbank verschachteln, machen Sie etwas falsch. Die Kombination dieser Sätze sollte auf der Datenbankseite erfolgen.

+0

Ja, das ist was ich getan habe, danke für die Erklärung. –

+4

Dies gilt nicht für alle Treiber und RDBMS. –

+0

sqlserver.jar kann nicht verschachteln, aber jtds.jar kann es tun. –

6

Die Ausnahme besagt, dass Ihr Ergebnis geschlossen ist. Sie sollten Ihren Code untersuchen und nach allen Orten suchen, an denen Sie einen ResultSet.close()-Anruf tätigen. Suchen Sie auch nach Statement.close() und Connection.close(). Sicher wird einer von ihnen angerufen, bevor rs.next() aufgerufen wird.

4

Sie geschlossen haben entweder die Connection oder Statement, die die ResultSet gemacht, die die ResultSet geschlossen ist als auch führen würden.

9

Außerdem kann nur eine Ergebnismenge von jeder Anweisung geöffnet werden. Wenn Sie also zwei Ergebnismengen gleichzeitig durchlaufen, stellen Sie sicher, dass sie auf verschiedenen Anweisungen ausgeführt werden. Das Öffnen einer zweiten Ergebnismenge in einer Aussage schließt implizit die erste. http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

4

Proper jdbc Aufruf sollte ungefähr so ​​aussehen:

try { 
    Connection conn; 
    Statement stmt; 
    ResultSet rs; 

    try { 
     conn = DriverManager.getConnection(myUrl,"",""); 
     stmt = conn.createStatement(); 
     rs = stmt.executeQuery(myQuery); 

     while (rs.next()) { 
      // process results 
     } 

    } catch (SqlException e) { 
     System.err.println("Got an exception! "); 
     System.err.println(e.getMessage()); 
    } finally { 
     // you should release your resources here 
     if (rs != null) { 
      rs.close(); 
     } 

     if (stmt != null) { 
      stmt.close(); 
     } 

     if (conn != null) { 
      conn.close(); 
     } 
    } 
} catch (SqlException e) { 
    System.err.println("Got an exception! "); 
    System.err.println(e.getMessage()); 
} 

können Sie Verbindung (oder Anweisung) erst, nachdem Sie von Ergebnismenge Ergebnis erhalten schließen. Am sichersten ist es, es in finally Block zu tun. Jedoch close() könnte auch through SqlException, daher der andere try-catch Block.

+1

Ich liebe diesen verschachtelten Versuch/Fang. Manchmal verabscheue ich wirklich JDBC. Es führt dieses Beispiel auf, aber Sie sollten das Resultset und die Anweisung auch wirklich schließen. Sie haben es einen richtigen JDBC-Aufruf genannt! – banjollity

+0

müssen Sie überprüfen, ob rs/stmt/conn nicht null ist ... –

+0

@DanielMagnusson Sie haben Recht. Ich habe die Antwort behoben. – Slartibartfast

17

Dies kann verschiedene Ursachen haben, einschließlich des von Ihnen verwendeten Treibers.

a) Einige Treiber erlauben keine verschachtelten Anweisungen. Abhängig davon, ob Ihr Treiber JDBC 3.0 unterstützt, sollten Sie beim Erstellen des Statement-Objekts den dritten Parameter überprüfen. Zum Beispiel hatte ich das gleiche Problem mit dem JayBird-Treiber für Firebird, aber der Code funktionierte gut mit dem Postgres-Treiber. Dann fügte ich dem Aufruf der createStatement-Methode den dritten Parameter hinzu und setzte ihn auf ResultSet.HOLD_CURSORS_OVER_COMMIT, und der Code funktionierte auch für Firebird einwandfrei.

static void testNestedRS() throws SQLException { 

    Connection con =null; 
    try { 
     // GET A CONNECTION 
     con = ConexionDesdeArchivo.obtenerConexion("examen-dest"); 
     String sql1 = "select * from reportes_clasificacion"; 

     Statement st1 = con.createStatement(
       ResultSet.TYPE_SCROLL_INSENSITIVE, 
       ResultSet.CONCUR_READ_ONLY, 
       ResultSet.HOLD_CURSORS_OVER_COMMIT); 
     ResultSet rs1 = null; 

     try { 
      // EXECUTE THE FIRST QRY 
      rs1 = st1.executeQuery(sql1); 

      while (rs1.next()) { 
       // THIS LINE WILL BE PRINTED JUST ONCE ON 
            // SOME DRIVERS UNLESS YOU CREATE THE STATEMENT 
       // WITH 3 PARAMETERS USING 
            // ResultSet.HOLD_CURSORS_OVER_COMMIT 
       System.out.println("ST1 Row #: " + rs1.getRow()); 

       String sql2 = "select * from reportes"; 
       Statement st2 = con.createStatement(
         ResultSet.TYPE_SCROLL_INSENSITIVE, 
         ResultSet.CONCUR_READ_ONLY); 

       // EXECUTE THE SECOND QRY. THIS CLOSES THE FIRST 
       // ResultSet ON SOME DRIVERS WITHOUT USING 
            // ResultSet.HOLD_CURSORS_OVER_COMMIT 

       st2.executeQuery(sql2); 

       st2.close(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } finally { 
      rs1.close(); 
      st1.close(); 
     } 

    } catch (SQLException e) { 

    } finally { 
     con.close(); 

    } 

} 

b) Es könnte einen Fehler in Ihrem Code geben. Denken Sie daran, dass Sie das Statement-Objekt nicht erneut verwenden können. Sobald Sie eine Abfrage für dasselbe Anweisungsobjekt erneut ausführen, werden alle geöffneten Resultsets, die der Anweisung zugeordnet sind, geschlossen. Stellen Sie sicher, dass Sie die Anweisung nicht schließen.

+0

Ich hatte das gleiche Problem mit Firebird JDBC-Treibern. Ich kann überprüfen, dass das 'ResultSet.HOLD_CURSORS_OVER_COMMIT' funktioniert. –

+0

Dieselben Probleme bei DB2-Treibern werden auch mit diesem Flag behoben! – bobbel

2

Überprüfen Sie, ob Sie die Methode, in der dieser Code ausgeführt wird, als static deklariert haben. Wenn es static ist, kann ein anderer Thread die ResultSet zurücksetzen.

1

Ich habe den gleichen Fehler, alles war korrekt, nur ich war mit der gleichen Anweisung Schnittstelle Objekt zum Ausführen und Aktualisieren der Datenbank. Nach dem Trennen, d.h. Verwenden verschiedener Objekte der Anweisungsschnittstelle zum Aktualisieren und Ausführen von Abfragen, löste ich diesen Fehler. d.h.Um dies zu vermeiden, verwenden Sie nicht dasselbe Anweisungsobjekt, um die Abfrage zu aktualisieren und auszuführen.

Verwandte Themen