Fermeture des connexions à la base de données en Java


121

Je suis un peu confus, je lisais ce qui suit sur http://en.wikipedia.org/wiki/Java_Database_Connectivity

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    //It's important to close the statement when you are done with it
    stmt.close();
}

Vous n'avez pas besoin de fermer la connexion conn? Que se passe-t-il vraiment si conn.close () ne se produit pas?

J'ai une application Web privée que je maintiens qui ne ferme actuellement aucun des formulaires, mais est-ce que l'important est vraiment celui de stmt, celui de conn ou les deux?

Le site continue de tomber par intermittence, mais le serveur continue de dire que c'est un problème de connexion à la base de données, je soupçonne qu'il n'est pas fermé, mais je ne sais pas lequel fermer le cas échéant.


Il est toujours recommandé de fermer les connexions vous-même, sans dépendre d'autres pilotes et modèles pour gérer la fermeture. L'échec de la fermeture de la connexion entraînera l'ouverture permanente des sockets et des ressources jusqu'à un crash (plus de scénario de ressources) ou un redémarrage.
Arun Joshla

Réponses:


196

Lorsque vous avez terminé d'utiliser votre Connection, vous devez le fermer explicitement en appelant sa close()méthode afin de libérer toutes les autres ressources de base de données (curseurs, poignées, etc.) sur lesquelles la connexion peut se maintenir.

En fait, le modèle sûr en Java est de fermer votre ResultSet, Statementet Connection(dans cet ordre) dans un finallybloc lorsque vous en avez terminé avec eux, quelque chose comme ça:

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* ignored */}
    }
}

Le finallybloc peut être légèrement amélioré en (pour éviter le contrôle nul):

} finally {
    try { rs.close(); } catch (Exception e) { /* ignored */ }
    try { ps.close(); } catch (Exception e) { /* ignored */ }
    try { conn.close(); } catch (Exception e) { /* ignored */ }
}

Mais, quand même, c'est extrêmement verbeux, vous finissez généralement par utiliser une classe d'assistance pour fermer les objets dans des méthodes d'assistance nulles et le finallybloc devient quelque chose comme ça:

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

Et, en fait, Apache Commons DbUtils a une DbUtilsclasse qui fait précisément cela, il n'est donc pas nécessaire d'écrire la vôtre.


3
Super aide, merci! Je n'ai pas attrapé ni pensé aux instructions conn! = Null.
onaclov2000

1
@ onaclov2000 Oui, rs, ps, connpeut être en nullfonction de l' endroit où les pauses de code. C'est pourquoi c'est ce qu'on appelle le modèle «sûr».
Pascal Thivent

12
@Pascal Thivent: En fait, nous n'avons pas besoin de les fermer tous. Le livre "Core Java Volume two - Advanced Features" a écrit: La closeméthode d'un Statementobjet ferme automatiquement l'associé ResultSetsi l'instruction a un jeu de résultats ouvert. De même, la closeméthode de la Connectionclasse se ferme tout Statementsde Connection.
Majid Azimi

12
@Majid: Sauf s'il s'agit d'une connexion groupée. Les déclarations fuiraient alors.
BalusC

1
@BalusC: Pouvez-vous expliquer ce qui se passe lorsqu'une connexion groupée est fermée en utilisant la méthode connection.close ()
Krsna Chaitanya

61

Il est toujours préférable de fermer les objets de base de données / ressources après utilisation. Il est préférable de fermer les objets de connexion, de jeu de résultats et d'instruction dans le finallybloc.

Jusqu'à Java7, toutes ces ressources doivent être fermées à l'aide d'un finallybloc. Si vous utilisez Java 7, pour fermer les ressources, vous pouvez procéder comme suit.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

//statements
}catch(....){}

Désormais, les objets con, stmt et rs font partie du bloc try et java ferme automatiquement ces ressources après utilisation.

J'espère que j'ai été utile.


Et si ma déclaration est implicite, c'est- ResultSet rs = conn.createStatement().executeQuery(sql);à- dire à l'intérieur du trybloc?
Antares42

1
Vous ne pourrez pas les référencer dans le bloc finally {} de clôture. Si une exception est levée, la méthode close () du ResultSet ne sera jamais invoquée
Dan

Que se passe-t-il si je ne les ferme pas?
Alex78191

si vous ne les fermez pas, des fuites de mémoire peuvent se produire.
Yadu Krishnan

14

Il suffit de fermer juste Statementet Connection. Il n'est pas nécessaire de fermer explicitement l' ResultSetobjet.

La documentation Java parle de java.sql.ResultSet:

Un objet ResultSet est automatiquement fermé par l'objet Statement qui l'a généré lorsque cet objet Statement est fermé, réexécuté ou utilisé pour récupérer le résultat suivant à partir d'une séquence de résultats multiples.


Merci BalusC pour les commentaires: "Je ne me fierais pas à cela. Certains pilotes JDBC échouent là-dessus."


25
Je ne me fierais pas à ça. Certains pilotes JDBC échouent là-dessus. Par exemple, Oracle avec "Curseurs ouverts maximum dépassés", etc. Fermez simplement explicitement toutes les ressources ouvertes, sans excuses.
BalusC

1
Je préférerais alors ne pas utiliser de pilotes non conformes aux spécifications
Enerccio

2
Comme le souligne BalusC, c'est une bonne programmation défensive de fermer explicitement la connexion au lieu de câbler une dépendance à un fournisseur particulier.
michaelok le

11

Oui. Vous devez fermer l'ensemble de résultats, l'instruction et la connexion. Si la connexion provient d'un pool, sa fermeture la renvoie en fait au pool pour une réutilisation.

Vous devez généralement le faire dans un finally{}bloc, de sorte que si une exception est levée, vous avez toujours la possibilité de la fermer.

De nombreux frameworks s'occuperont de ce problème d'allocation / désallocation des ressources pour vous. par exemple le JdbcTemplate de Spring . Apache DbUtils a des méthodes pour s'occuper de la fermeture du jeu de résultats / de l'instruction / de la connexion, qu'elle soit nulle ou non (et intercepter les exceptions à la fermeture), ce qui peut également aider.


1
Quand j'insère une éclipse "enfin" aime la mettre en évidence en me disant que c'est faux. cela devrait-il aller après les blocs catch?
onaclov2000

Oui. essayez {} catch {} enfin {}. Le catch {} est facultatif, btw. Tout comme le finalement {}
Brian Agnew

J'ai déplacé les instructions "close" vers la fin, mais elles disent simplement "sqlexception", des suggestions?
onaclov2000

1
close () lève une exception SQLException. Vous devez gérer cela. Voir DbUtils.closeQuietly () pour gérer cela en silence.
Brian Agnew

> Que se passe-t-il vraiment si conn.close () ne se produit pas?
Alex78191

8

En fait, il est préférable d'utiliser un bloc try-with-resources et Java fermera toutes les connexions pour vous lorsque vous quitterez le bloc try.

Vous devez le faire avec tout objet qui implémente AutoClosable.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

L'appel à getDatabaseConnection est juste composé. Remplacez-le par un appel qui vous permet d'obtenir une connexion SQL JDBC ou une connexion à partir d'un pool.


Vous n'avez donc pas à fermer manuellement la connexion dans ce cas?
Colin D

1
Correct. Vous n'êtes pas obligé de fermer explicitement la connexion. Il sera fermé lorsque la fin du bloc de code d'essai sera atteinte.
Joe

7

Oui, vous devez fermer la connexion. Sinon, le client de base de données gardera généralement la connexion socket et les autres ressources ouvertes.


... jusqu'à ce qu'il sorte. Cela attache diverses ressources finies côté client et côté serveur. Si un client fait trop ce genre de chose, cela peut causer des problèmes au client lui-même, au service de base de données et peut-être même à d'autres applications s'exécutant sur une machine client ou serveur.
Stephen C
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.