Question

Je suis en train de réviser le code (en utilisant principalement des outils tels que FindBugs) de l'un de nos projets pour animaux de compagnie et FindBugs a indiqué que le code suivant était 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 libérait peut-être pas de ressources. J'ai compris que ResultSet et Statement n'étaient pas fermés. Je les ai donc fermés enfin:

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

Mais j’ai rencontré le schéma ci-dessus dans de nombreux projets (de nombreuses entreprises) et personne ne fermait les ResultSets ou les instructions.

Avez-vous eu des problèmes avec les ResultSets et les instructions non fermées lorsque la connexion est fermée?

J'ai trouvé seulement this et il fait référence au problème rencontré par Oracle fermer 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.

Était-ce utile?

La solution

Un problème avec SEULEMENT la fermeture de la connexion et non le jeu de résultats est que si votre code de gestion de connexion utilise le pool de connexions, le connection.close () remettrait simplement 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 d’être explicitement fermée.

Autres conseils

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

"ORA-01000: maximum open cursors exceeded"

Donc: fermez toujours votre ResultSet!

Vous devez toujours fermer toutes les ressources JDBC de manière explicite. Comme l'ont déjà dit Aaron et John, la fermeture d'une connexion ne la renverra généralement qu'à un pool. 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) {
        }
    }
}

Oracle vous signalera des erreurs sur 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 ensembles de résultats ouverts, et la fermeture d'une instruction ferme tous les ensembles de résultats, mais je ne vois rien concernant la fermeture d'une connexion fermera les ressources créées.

Toutes ces informations sont laissées au fournisseur du pilote JDBC.

Il est toujours plus sûr de tout fermer explicitement. Nous avons écrit une classe util qui encapsule 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 censément lancées. .

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

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

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

Que la meilleure pratique consiste à tout fermer.

Je travaille dans un grand environnement Web J2EE. Nous avons plusieurs bases de données qui peuvent être connectées à une seule demande. Nous avons commencé à avoir des blocages logiques dans certaines de nos applications. Le problème était le suivant:

  1. L'utilisateur demande une page
  2. Le serveur se connecte à la base de données 1
  3. Sélection de serveur sur le DB 1
  4. Le serveur " ferme " connexion à la base de données 1
  5. Le serveur se connecte à la base de données 2
  6. Dans l'impasse!

Cela est dû à deux raisons: nous avons enregistré un trafic beaucoup plus important que la normale et la spécification J2EE par défaut ne ferme pas 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 s’ils ont été correctement fermés.

Pour résoudre ce problème, vous devez utiliser les références de ressources dans le fichier web.xml pour vos connexions à la base de données et définir le paramètre res-sharing-scope 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>

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

En Java, les instructions (et non les ensembles de résultats) sont corrélées aux curseurs dans Oracle. Il est préférable de fermer les ressources que vous ouvrez car un comportement inattendu peut se produire concernant la JVM et les ressources système.

De plus, certains frameworks de mise en pool JDBC regroupent des instructions et des connexions. Par conséquent, ne pas les fermer peut ne pas marquer ces objets comme étant 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 existe une raison de l’appeler, et l’ignorer est fait à vos risques et périls.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top