Chiusura delle connessioni al database in Java


121

Sto diventando un po 'confuso, stavo leggendo quanto segue da 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();
}

Non è necessario chiudere la connessione conn? Cosa succede realmente se conn.close () non si verifica?

Ho un'app Web privata che sto mantenendo che al momento non chiude nessuna delle due forme, ma quella importante è davvero quella stmt, quella conn o entrambe?

Il sito continua a interrompersi a intermittenza ma il server continua a dire che si tratta di un problema di connessione al database, il mio sospetto è che non venga chiuso, ma non so quale chiudere.


È sempre buona norma chiudere le connessioni da soli, senza dipendere da altri driver e modelli per gestire la chiusura. La mancata chiusura della connessione comporterà l'apertura dei socket e delle risorse per sempre fino a un arresto anomalo (nessun altro scenario di risorse) o al riavvio.
Arun Joshla

Risposte:


196

Quando hai finito di usare your Connection, devi chiuderlo esplicitamente chiamando il suo close()metodo per rilasciare qualsiasi altra risorsa di database (cursori, handle, ecc.) A cui la connessione potrebbe trattenere.

In realtà, il modello sicuro in Java è chiudere il tuo ResultSet, Statemente Connection(in quell'ordine) in un finallyblocco quando hai finito con loro, qualcosa del genere:

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 */}
    }
}

Il finallyblocco può essere leggermente migliorato in (per evitare il controllo nullo):

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

Tuttavia, questo è estremamente dettagliato, quindi generalmente si finisce per utilizzare una classe helper per chiudere gli oggetti in metodi helper null-safe e il finallyblocco diventa qualcosa del genere:

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

E, in realtà, Apache Commons DbUtils ha una DbUtilsclasse che lo fa precisamente, quindi non è necessario scriverne una propria.


3
Aiuto fantastico, grazie! Non ho capito o pensato alle istruzioni conn! = Null.
onaclov2000

1
@ onaclov2000 Sì, rs, ps, connpuò essere nulla seconda di dove il codice si rompe. Ecco perché questo è noto come il modello "sicuro".
Pascal Thivent

12
@Pascal Thivent: In realtà non abbiamo bisogno di chiuderli tutti. Il libro "Core Java Volume Two - Advanced Features" ha scritto: Il closemetodo di un Statementoggetto chiude automaticamente l'associato ResultSetse l'istruzione ha un set di risultati aperto. Allo stesso modo, il closemetodo della Connectionclasse chiude tutti Statementsi file Connection.
Majid Azimi

12
@ Majid: a meno che non si tratti di una connessione in pool. Le dichiarazioni sarebbero poi trapelate.
BalusC

1
@BalusC: Puoi spiegare cosa succede quando una connessione in pool viene chiusa usando il metodo connection.close ()
Krsna Chaitanya

61

È sempre meglio chiudere il database / gli oggetti risorsa dopo l'uso. Meglio chiudere la connessione, l'insieme di risultati e gli oggetti istruzione nel finallyblocco.

Fino a Java7, tutte queste risorse devono essere chiuse utilizzando un finallyblocco. Se stai usando Java 7, per chiudere le risorse puoi fare come segue.

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

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

Ora, gli oggetti con, stmt e rs diventano parte del blocco try e java chiude automaticamente queste risorse dopo l'uso.

Spero di essere stato d'aiuto.


E se la mia dichiarazione è implicita, cioè ResultSet rs = conn.createStatement().executeQuery(sql);all'interno del tryblocco?
Antares42

1
Non sarai in grado di fare riferimento a loro nel blocco di chiusura finalmente {}. Se viene generata un'eccezione, il metodo close () del ResultSet non verrà mai richiamato
Dan

Cosa succede se non li chiudo?
Alex78191

se non li chiudi, possono verificarsi perdite di memoria.
Yadu Krishnan

14

È sufficiente chiudere solo Statemente Connection. Non è necessario chiudere esplicitamente l' ResultSetoggetto.

La documentazione Java dice su java.sql.ResultSet:

Un oggetto ResultSet viene chiuso automaticamente dall'oggetto Statement che lo ha generato quando tale oggetto Statement viene chiuso, rieseguito o utilizzato per recuperare il risultato successivo da una sequenza di più risultati.


Grazie BalusC per i commenti: "Non farei affidamento su questo. Alcuni driver JDBC falliscono su questo."


25
Non ci farei affidamento. Alcuni driver JDBC non riescono a farlo. Es. Oracle con "Numero massimo di cursori aperti superato", ecc. Chiudi esplicitamente tutte le risorse aperte, niente scuse.
BalusC

1
Preferirei non utilizzare driver non conformi alle specifiche allora
Enerccio

2
Come sottolinea BalusC, è una buona programmazione difensiva chiudere esplicitamente la connessione invece di cablare una dipendenza da un particolare provider.
michaelok

11

Sì. È necessario chiudere il gruppo di risultati, l'istruzione e la connessione. Se la connessione proviene da un pool, chiudendola viene effettivamente rimandata al pool per il riutilizzo.

In genere devi farlo in un finally{}blocco, in modo tale che se viene generata un'eccezione, hai ancora la possibilità di chiuderla.

Molti framework si occuperanno di questo problema di allocazione / deallocazione delle risorse per te. ad esempio JdbcTemplate di Spring . Apache DbUtils ha metodi per occuparsi della chiusura del gruppo di risultati / istruzione / connessione sia null o meno (e rilevare le eccezioni alla chiusura), il che può anche aiutare.


1
Quando inserisco un'eclissi "finalmente" mi piace evidenziarla dicendomi che è sbagliata. dovrebbe andare dopo i blocchi di cattura?
onaclov2000

Sì. try {} catch {} finally {}. La cattura {} è facoltativa, btw. Proprio come il finalmente {}
Brian Agnew

Ho spostato le istruzioni "close" in finalmente, ma dicono solo "sqlexception", qualche suggerimento?
onaclov2000

1
close () genera una SQLException. Devi gestirlo. Vedere DbUtils.closeQuietly () per gestire questa operazione silenziosamente.
Brian Agnew

> Cosa succede realmente se conn.close () non si verifica?
Alex78191

8

In realtà, è meglio se usi un blocco try-with-resources e Java chiuderà tutte le connessioni per te quando esci dal blocco try.

Dovresti farlo con qualsiasi oggetto che implementa 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.");
}

La chiamata a getDatabaseConnection è appena stata creata. Sostituirlo con una chiamata che fornisce una connessione SQL JDBC o una connessione da un pool.


Quindi non è necessario chiudere manualmente la connessione in questo caso?
Colin D

1
Corretta. Non è necessario chiudere esplicitamente la connessione. Verrà chiuso quando viene raggiunta la fine del blocco del codice di prova.
Joe

7

Sì, è necessario chiudere la connessione. In caso contrario, il client del database manterrà in genere aperte la connessione socket e altre risorse.


... finché non esce. Ciò lega varie risorse finite sul lato client e server. Se un client fa troppo questo genere di cose, può causare problemi al client stesso, al servizio di database e possibilmente anche ad altre applicazioni in esecuzione sul computer client o server.
Stephen C,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.