2010-02-08 19 views
83

io sono sempre un po 'confuso, stavo leggendo il seguito da http://en.wikipedia.org/wiki/Java_Database_Connectivitychiusura Connessioni di database in Java

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 ti necessario chiudere la connessione conn? Cosa sta succedendo veramente se conn.close() non si verifica?

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

Il sito continua ad andare giù a intermittenza ma il server continua a dire che si tratta di un problema di connessione al database, il mio sospetto è che non sia stato chiuso, ma non so se chiuderlo.

risposta

150

Quando hai finito di usare il tuo Connection, devi chiuderlo esplicitamente chiamando il suo metodo close() per poter rilasciare qualsiasi altra risorsa del database (cursori, maniglie, ecc.) Sulla quale la connessione può essere tenuta.

In realtà, il modello di sicurezza in Java è quello di chiudere la vostra ResultSet, Statement, e Connection (in quest'ordine) in un blocco finally quando si è fatto con loro, qualcosa di simile:

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 finally blocco può essere leggermente migliorata in (per evitare il controllo null):

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

Ma, ancora, questo è estremamente dettagliato in modo generalmente finisce per utilizzare una classe di supporto a C perdere gli oggetti in metodi di supporto nulli di sicurezza e il blocco finally diventa qualcosa di simile:

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

E, in realtà, il Apache Commons DbUtils ha una classe DbUtils che sta appunto facendo che quindi non c'è bisogno di scrivere il proprio.

+3

Un aiuto fantastico, grazie! Non ho preso o pensato alle dichiarazioni conn! = Null. – onaclov2000

+1

@ onaclov2000 Sì, 'rs',' ps', 'conn' potrebbe essere' null' a seconda di dove si rompe il codice. Ecco perché questo è noto come il modello "sicuro". –

+10

@Pascal Thivent: in realtà non è necessario chiuderli tutti. Il libro "Core Java Volume due - Funzioni avanzate" ha scritto: Il metodo 'close' di un oggetto' Statement' chiude automaticamente il 'ResultSet' associato se l'istruzione ha un set di risultati aperto. Allo stesso modo, il metodo 'close' della classe' Connection' chiude tutti 'Statements' di' Connection'. –

6

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

+0

... finché non esce. Questo riduce varie risorse finite sul lato client e server. Se un client fa troppo questo tipo di cose, può causare problemi per il client stesso, il servizio di database ed eventualmente anche per altre applicazioni in esecuzione su client o server. –

8

Sì. Devi chiudere il set di risultati, la dichiarazione e la connessione. Se la connessione proviene da un pool, la sua chiusura lo invia di nuovo al pool per il riutilizzo.

In genere è necessario farlo in un blocco finally{}, in modo tale che se viene generata un'eccezione, si ha comunque la possibilità di chiuderla.

Molti framework si prenderanno cura di questo problema di allocazione delle risorse/deallocazione. per esempio. Spring's JdbcTemplate. Apache DbUtils ha metodi da seguire dopo la chiusura del set di risultati/dell'istruzione/connessione sia null o meno (e cattura le eccezioni alla chiusura), il che può essere di aiuto.

+0

Quando inserisco un'eclissi "finalmente" mi piace evidenziarlo dicendomi che è sbagliato. questo dovrebbe andare dopo i blocchi di cattura? – onaclov2000

+2

Crap, ho appena risposto alla mia domanda e l'ho provato, mi dispiace – onaclov2000

+0

Sì. try {} catch {} finally {}. Il catch {} è facoltativo, btw. Proprio come alla fine {} –

9

E 'sufficiente chiudere solo Statement e Connection. Non è necessario chiudere esplicitamente l'oggetto ResultSet.

documentazione

Java dice di java.sql.ResultSet:

un oggetto ResultSet viene automaticamente chiusa dal oggetto Statement che lo ha generato quando l'oggetto Statement è chiuso, rieseguito, o viene utilizzato per recuperare il risultato successivo da un sequenza di risultati multipli.


Grazie BalusC per i commenti: "Non vorrei fare affidamento su che alcuni driver JDBC non su questo.".

+14

Non mi fiderei di questo. Alcuni driver JDBC non riescono su questo. Per esempio. Oracle con "Cursori aperti massimi superati", ecc. Chiudi esplicitamente tutte le risorse aperte, nessuna scusa. – BalusC

41

È sempre preferibile chiudere gli oggetti database/risorsa dopo l'uso. È meglio chiudere gli oggetti connessione, risultati e istruzione nel blocco finally.

Fino a Java7, tutte queste risorse devono essere chiuse utilizzando un blocco finally. Se si utilizza Java 7, per chiudere le risorse è possibile procedere come segue.

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

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

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

Spero di essere stato utile.

+0

Cosa succede se la mia istruzione è implicita, ad esempio '' ResultSet rs = conn.createStatement(). ExecuteQuery (sql); '' all'interno del blocco '' try''? – Antares42

+1

Non sarà possibile farvi riferimento nel blocco finally {} per la chiusura. Se viene lanciata un'eccezione, il metodo close() del ResultSet non verrà mai richiamato – Dan

0

In realtà, è meglio se si utilizza un blocco try-with-resources e Java chiuderà tutte le connessioni al momento dell'uscita dal blocco try.

È necessario eseguire questa operazione 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 è stata appena creata. Sostituirlo con una chiamata che ti ottiene una connessione JDBC SQL o una connessione da un pool.

Problemi correlati