49 votes

ResultSet non fermé lorsque la connexion est fermée ?

J'ai fait une revue de code (en utilisant principalement des outils comme FindBugs) d'un de nos projets favoris et FindBugs a marqué le code suivant comme erroné (pseudocode) :

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

L'erreur était que ce code pouvait ne pas libérer de ressources. Je me suis rendu compte que le ResultSet et le Statement n'étaient pas fermés, alors je les ai fermés dans finally :

finally{
    try{
        rs.close()
    }catch(SqlException se){
        //log it
    }
    try{
        stmt.close();
    }catch(SqlException se){
        //log it
    }
    conn.close();
}

Mais j'ai rencontré le modèle ci-dessus dans de nombreux projets (de plusieurs entreprises), et personne ne fermait les ResultSets ou les Statements.

Avez-vous eu des problèmes avec les ResultSets et les Statements qui ne sont pas fermés lorsque la connexion est fermée ?

J'ai trouvé seulement ce et il fait référence au fait qu'Oracle a des problèmes avec la fermeture des ResultSets lors de la fermeture des Connexions (nous utilisons une base de données Oracle, d'où mes corrections). java.sql.api ne dit rien dans la javadoc Connection.close().

0 votes

Je recommande vivement d'utiliser Apache commons-dbutils ( commons.apache.org/dbutils ) Il s'agit d'une bibliothèque JDBC légère qui nettoie vraiment beaucoup de code JDBC passe-partout.

2 votes

C'est le genre d'erreurs que l'on obtient lorsqu'on ne ferme pas les objets concernés - "ORA-01000 : le nombre maximum de curseurs ouverts est dépassé". stackoverflow.com/questions/12192592/

0 votes

Curseur de base de données - stackoverflow.com/questions/3861558/ Un curseur est un outil qui vous permet d'itérer les enregistrements d'un ensemble. Il possède les concepts d'ordre et d'enregistrement courant.

52voto

Aaron Points 5589

Un problème lié au fait de fermer UNIQUEMENT la connexion et non le jeu de résultats est que si votre code de gestion des connexions utilise la mise en commun des connexions, l'opération de fermeture de l'ensemble de résultats ne peut pas être effectuée. connection.close() ne ferait que remettre la connexion dans le pool. De plus, certaines bases de données ont une ressource curseur sur le serveur qui ne sera pas libérée correctement à moins qu'elle ne soit explicitement fermée.

14 votes

La javadocs pour la méthode Connection#close dit que "libère immédiatement la base de données et les ressources JDBC de cet objet Connection". Je pense que le problème est que certaines mauvaises implémentations ne font pas le bon travail. Lorsque les pools ne ferment pas les ressources liées, font-ils la mauvaise chose ?

2 votes

Les pilotes JDBC de la plupart des grands fournisseurs correspondent à la spécification. Cependant, la plupart des serveurs d'applications (si ce n'est tous) maintiennent un pool de connexions. Ils enveloppent la connexion native et réimplémentent des méthodes telles que close() afin que les connexions puissent être "mises en commun". Cela signifie que si vous travaillez dans ces environnements, vous DEVEZ fermer vous-même les ressources telles que les Statements et les ResultSets.

4 votes

@Ryan Fernandes : Eh bien, certains pools vous donnent simplement un objet connectionProxy qui enregistre toutes les déclarations ouvertes sur lui. Lorsqu'il est renvoyé dans le pool, il ferme toutes les déclarations ouvertes.

29voto

neu242 Points 4538

J'ai eu des problèmes avec des ResultSets non fermés dans Oracle, même si la connexion était fermée. L'erreur que j'ai obtenue est la suivante

"ORA-01000: maximum open cursors exceeded"

Donc : Fermez toujours votre ResultSet !

1 votes

+1 - pour avoir mentionné les conséquences de la non-fermeture des ressources.

19voto

Stefan Schweizer Points 151

Vous devez toujours fermer explicitement toutes les ressources JDBC. Comme Aaron et John l'ont déjà dit, la fermeture d'une connexion ne fera souvent que la remettre dans un pool et tous les pilotes JDBC ne sont pas implémentés exactement de la même manière.

Voici une méthode utilitaire qui peut être utilisée à partir d'un bloc final :

public static void closeEverything(ResultSet rs, Statement stmt,
        Connection con) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
}

6 votes

Mec, peut-être qu'on a besoin d'une interface Closable, hein ?

2 votes

ResultSet sont fermés automatiquement lorsque vous fermez le Statement. (Voir la JavaDoc download.oracle.com/javase/1.4.2/docs/api/java/sql/ )

0 votes

Merci de poster. J'aime cette idée.

9voto

John Gardner Points 10882

Dans ce cas, Oracle vous donnera des erreurs concernant les curseurs ouverts.

Selon : http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

il semble que la réutilisation d'une instruction ferme tous les jeux de résultats ouverts, et que la fermeture d'une instruction ferme tous les jeux de résultats, mais je ne vois rien qui indique que la fermeture d'une connexion ferme toutes les ressources qu'elle a créées.

Tous ces détails sont laissés au fournisseur du pilote JDBC.

Il est toujours plus sûr de tout fermer explicitement. Nous avons écrit une classe util qui enveloppe tout avec try{ xxx } catch (Throwable {} afin que vous puissiez simplement appeler Utils.close(rs) et Utils.close(stmt), etc. sans avoir à vous soucier des exceptions que le scan de fermeture est censé lancer.

0 votes

mais je ne vois rien qui indique que la fermeture d'une connexion fermera les ressources qu'elle a créées. [docs.oracle.com/javase/6/docs/api/java/sql/](http://docs.oracle.com/javase/6/docs/api/java/sql/Connection.html#close()) libère la base de données de cet objet Connexion et les ressources JDBC immédiatement Mais oui, c'est toujours mieux de tout fermer.

8voto

Horcrux7 Points 8369

L'ODBC Bridge peut produire une fuite de mémoire avec certains pilotes ODBC.

Si vous utilisez un bon pilote JDBC, vous ne devriez pas avoir de problèmes pour fermer la connexion. Mais il y a deux problèmes :

  • Savez-vous si vous avez un bon conducteur ?
  • Utiliserez-vous d'autres pilotes JDBC à l'avenir ?

Que la meilleure pratique est de tout fermer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X