2009-06-01 3 views
21

Dès que mon code arrive à ma boucle while(rs.next()), il produit l'exception ResultSet fermée. Quelles sont les causes de cette exception et comment puis-je la corriger?Comment puis-je éviter ResultSet est une exception fermée dans Java?

EDIT: Je remarque dans mon code que j'imbrication boucle while(rs.next()) avec un autre (rs2.next()), les deux ensembles de résultats provenant de la même DB, est-ce un problème?

+5

Ajoutez une liste de votre code. – JeeBee

Répondre

39

Il semble que vous ayez exécuté une autre instruction dans la même connexion avant de parcourir le jeu de résultats à partir de la première instruction. Si vous imbriquez le traitement de deux ensembles de résultats à partir de la même base de données, vous faites quelque chose de mal. La combinaison de ces ensembles devrait être faite du côté de la base de données.

+0

ouais c'est ce que j'ai fait, merci pour l'explication. –

+4

Cela n'est pas vrai pour tous les pilotes et les SGBDR. –

+0

sqlserver.jar ne peut pas l'imbriquer, mais jtds.jar peut le faire. –

6

L'exception indique que votre résultat est fermé. Vous devez examiner votre code et rechercher tout l'emplacement où vous émettez un appel ResultSet.close(). Recherchez également Statement.close() et Connection.close(). Pour sûr, l'un d'entre eux est appelé avant que le rs.next() soit appelé.

4

Vous avez peut-être fermé soit le Connection ou Statement qui a fait la ResultSet, qui conduirait à la ResultSet étant fermée aussi bien.

9

De plus, vous ne pouvez avoir qu'un jeu de résultats ouvert à partir de chaque instruction. Donc, si vous itérez deux ensembles de résultats en même temps, assurez-vous qu'ils sont exécutés sur des instructions différentes. L'ouverture d'un second jeu de résultats sur une instruction fermera implicitement la première.

4

appel jdbc approprié devrait ressembler à:

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

vous pouvez fermer la connexion (ou déclaration) seulement après que vous obtenir le résultat du jeu de résultats. Le moyen le plus sûr est de le faire dans le bloc finally. Cependant close() pourrait également être SqlException, d'où l'autre bloc try-catch.

+1

Dois adorer ce try/catch imbriqué. Parfois, je déteste vraiment JDBC. Cela gonfle cet exemple mais vous devriez vraiment fermer le resultset et la déclaration aussi. Vous l'avez appelé un appel JDBC approprié! – banjollity

+0

besoin d'une vérification si rs/stmt/conn n'est pas nulle ... –

+0

@DanielMagnusson Vous avez raison. J'ai corrigé la réponse. – Slartibartfast

17

Cela peut être dû à un certain nombre de raisons, y compris le pilote que vous utilisez. A) Certains pilotes n'autorisent pas les instructions imbriquées. Selon que votre pilote prend en charge JDBC 3.0, vous devez vérifier le troisième paramètre lors de la création de l'objet Statement. Par exemple, j'ai eu le même problème avec le pilote JayBird à Firebird, mais le code a bien fonctionné avec le pilote postgres. Ensuite, j'ai ajouté le troisième paramètre à l'appel de méthode createStatement et l'ai défini sur ResultSet.HOLD_CURSORS_OVER_COMMIT, et le code a également fonctionné correctement pour Firebird. B) Il pourrait y avoir un bogue dans votre code.

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

    } 

} 

Souvenez-vous que vous ne pouvez pas réutiliser l'objet Statement, une fois que vous avez réexécuté une requête sur le même objet d'instruction, tous les resultsets ouverts associés à l'instruction sont fermés. Assurez-vous de ne pas fermer la déclaration.

+0

J'avais le même problème avec les pilotes Firebird JDBC. Je peux vérifier que 'ResultSet.HOLD_CURSORS_OVER_COMMIT' fonctionne. –

+0

Les mêmes problèmes sur les pilotes DB2 sont également résolus avec ce drapeau! – bobbel

2

Vérifiez si vous avez déclaré la méthode où ce code s'exécute en tant que static. Si c'est static il peut y avoir un autre thread réinitialiser le ResultSet.

1

J'ai la même erreur tout était correct seulement j'utilisais même objet d'instruction de déclaration pour exécuter et mettre à jour la base de données. Après la séparation, c'est-à-dire l'utilisation de différents objets de l'interface d'instruction pour la mise à jour et l'exécution de la requête, j'ai résolu cette erreur. c'est à dire.Ne vous en débarrassez pas, n'utilisez pas l'objet statement même pour la mise à jour et l'exécution de la requête.

Questions connexes