web-dev-qa-db-fra.com

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

J'ai fait un examen du code (principalement en utilisant des outils comme FindBugs) de l'un de nos projets pour animaux de compagnie 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 ne pouvait pas libérer de ressources. J'ai compris que ResultSet et Statement n'étaient pas fermés, alors je les ai finalement fermés:

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 (provenant de plusieurs entreprises), et personne ne fermait les ensembles de résultats ou les relevés.

Avez-vous rencontré des problèmes avec la fermeture des ensembles de résultats et des instructions lorsque la connexion est fermée?

J'ai trouvé seulement this et cela fait référence à Oracle ayant des problèmes avec la fermeture de ResultSets lors de la fermeture de Connections (nous utilisons Oracle db, d'où mes corrections). Java.sql.api ne dit rien dans Connection.close () javadoc.

49
jb.

Un problème avec la fermeture de la connexion UNIQUEMENT et non l'ensemble de résultats est que si votre code de gestion de connexion utilise le regroupement de connexions, la connection.close() remettra simplement la connexion dans le pool. En outre, certaines bases de données ont une ressource de curseur sur le serveur qui ne sera pas libérée correctement sauf si elle est explicitement fermée.

52
Aaron

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

"ORA-01000: maximum open cursors exceeded"

Donc: fermez toujours votre ResultSet!

28
neu242

Vous devez toujours fermer toutes les ressources JDBC de manière explicite. Comme Aaron et John l'ont déjà dit, la fermeture d'une connexion ne la renvoie souvent qu'à 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 finally:

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) {
        }
    }
}
19
Stefan Schweizer

Oracle vous donnera des erreurs sur les curseurs ouverts dans ce cas.

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 ensembles de résultats ouverts et la fermeture d'une instruction ferme tous les ensembles de résultats, mais je ne vois rien sur la fermeture d'une connexion qui fermera les ressources qu'elle a créées.

Tous ces détails sont laissés au fournisseur de pilotes 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 {} pour 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é jeter .

9
John Gardner

Le pont ODBC 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ème avec la fermeture de la connexion. Mais il y a 2 problèmes:

  • Savez-vous si vous avez un bon chauffeur?
  • Allez-vous utiliser d'autres pilotes JDBC à l'avenir?

Que la meilleure pratique est de tout fermer.

8
Horcrux7

Je travaille dans un grand environnement web J2EE. Nous avons plusieurs bases de données auxquelles vous pouvez vous connecter en une seule demande. Nous avons commencé à obtenir des blocages logiques dans certaines de nos applications. Le problème était le suivant:

  1. L'utilisateur demanderait la page
  2. Le serveur se connecte à DB 1
  3. Le serveur sélectionne sur DB 1
  4. Le serveur "ferme" la connexion à DB 1
  5. Le serveur se connecte à DB 2
  6. Impasse!

Cela s'est produit pour 2 raisons, nous connaissions un volume de trafic beaucoup plus élevé que la normale et la spécification J2EE par défaut ne ferme pas réellement votre connexion tant que le thread n'a pas terminé son exécution. Ainsi, dans l'exemple ci-dessus, l'étape 4 n'a jamais réellement fermé la connexion, même si elle a été correctement fermée.

Pour résoudre ce problème, vous devez utiliser des références de ressources dans le web.xml pour vos connexions à la base de données et vous devez définir la portée de partage de res sur non partageable.

Exemple:

<resource-ref>
    <description>My Database</description>
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
8
Konrad

J'ai certainement vu des problèmes avec les ResultSets non fermés, et que peut-il faire mal de les fermer tout le temps, non? Le manque de fiabilité de devoir se souvenir de le faire est l'une des meilleures raisons de passer à des cadres qui gèrent ces détails pour vous. Cela n'est peut-être pas possible dans votre environnement de développement, mais j'ai eu beaucoup de chance en utilisant Spring pour gérer les transactions JPA. Les détails désordonnés de l'ouverture des connexions, des instructions, des jeux de résultats et de l'écriture de blocs try/catch/finally trop compliqués (avec les blocs try/catch dans le bloc finally!) pour les refermer disparaissent, laissant vous pour réellement faire du travail. Je recommande fortement de migrer vers ce type de solution.

4
JavadocMD

En Java, les instructions (et non les ensembles de résultats) sont en corrélation avec les curseurs d'Oracle. Il est préférable de fermer les ressources que vous ouvrez car un comportement inattendu peut se produire en ce qui concerne la JVM et les ressources système.

En outre, certains frameworks de mise en commun JDBC regroupent les instructions et les connexions. Par conséquent, leur fermeture peut ne pas marquer ces objets comme libres dans le pool et entraîner des problèmes de performances dans le framework.

En général, s'il existe une méthode close () ou destroy () sur un objet, il y a une raison de l'appeler et de l'ignorer se fait à vos risques et périls.

4
Spencer Kormos