web-dev-qa-db-fra.com

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

Je suis un peu confus, je lisais le texte ci-dessous dans 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();
}

N'avez-vous pas besoin de fermer la connexion? Que se passe-t-il réellement si conn.close () ne se produit pas?

Je maintiens une application Web privée qui ne ferme actuellement aucune de ces deux formes, mais l’importante est-elle vraiment la solution la plus récente, la connexion ou les deux?

Le site n'arrête pas de fonctionner de façon intermittente, mais le serveur ne cesse de dire qu'il s'agit d'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, le cas échéant, doit fermer.

107
onaclov2000

Lorsque vous en avez terminé avec votre Connection, vous devez explicitement le fermer en appelant sa méthode close() afin de libérer toutes les autres ressources de la base de données (curseurs, descripteurs, etc.) auxquelles la connexion est susceptible de rester.

En fait, le modèle de sécurité dans Java consiste à fermer votre ResultSet, Statement et Connection (dans cet ordre) dans un bloc finally lorsque vous avez terminé, à peu près comme ceci:

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 bloc finally peut être légèrement amélioré (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, cela reste extrêmement verbeux et vous finissez généralement par utiliser une classe helper pour fermer les objets dans les méthodes helper null-safe et le bloc finally devient quelque chose comme ça:

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

Et, en réalité, le Apache Commons DbUtils a une classe DbUtils qui le fait précisément; il n'est donc pas nécessaire d'écrire votre propre classe.

178
Pascal Thivent

Il est toujours préférable de fermer les objets de base de données/ressource après utilisation. Mieux vaut fermer les objets connection, resultset et statement dans le bloc finally.

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

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.

55
Yadu Krishnan

Il suffit de fermer juste Statement et Connection. Il n'est pas nécessaire de fermer explicitement l'objet ResultSet.

La documentation Java dit à propos 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 est utilisé pour extraire le résultat suivant à partir d'une séquence de plusieurs résultats.


Merci BalusC pour les commentaires: "Je ne m'appuierais pas sur cela. Certains pilotes JDBC échouent à ce sujet."

13
Grigori A.

Oui. Vous devez fermer le résultat, la déclaration et la connexion. Si la connexion provient d'un pool, sa fermeture la renvoie au pool pour la réutilisation.

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

De nombreux frameworks s'occuperont de ce problème d'allocation/désallocation de ressources. par exemple. Le printemps JdbcTemplate . Apache DbUtils possède des méthodes pour surveiller la fermeture du jeu de résultats/de la déclaration/de la connexion, qu'elle soit nulle ou non (et intercepter des exceptions lors de la fermeture), ce qui peut également aider.

11
Brian Agnew

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

7
Alex Miller

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

Vous devriez le faire avec n'importe quel 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 constitué. Remplacez-le par un appel qui vous permet d'obtenir une connexion SQL JDBC ou une connexion d'un pool.

5
Joe