Domanda

Ho fatto la revisione del codice (principalmente utilizzando strumenti come FindBugs) di uno dei nostri progetti per animali domestici e FindBugs ha contrassegnato il seguente codice come errato (pseudocodice):

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

L'errore era che questo codice non poteva rilasciare risorse. Ho capito che ResultSet e Statement non erano chiusi, quindi li ho chiusi finalmente:

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

Ma ho riscontrato il modello sopra riportato in molti progetti (da un bel po 'di aziende) e nessuno stava chiudendo Set di risultati o dichiarazioni.

Hai riscontrato problemi con i set di risultati e le dichiarazioni non chiusi quando la connessione è chiusa?

Ho trovato solo questo e si riferisce a Oracle che ha problemi con chiusura dei ResultSet alla chiusura di Connections (usiamo Oracle db, quindi le mie correzioni). java.sql.api non dice nulla in Connection.close () javadoc.

È stato utile?

Soluzione

Un problema con la chiusura SOLO della connessione e non con il set di risultati è che se il codice di gestione della connessione utilizza il pool di connessioni, connection.close () rimetterebbe semplicemente la connessione nel pool . Inoltre, alcuni database hanno una risorsa cursore sul server che non verrà liberata correttamente a meno che non sia esplicitamente chiusa.

Altri suggerimenti

Ho avuto problemi con i ResultSet non chiusi in Oracle, anche se la connessione era chiusa. L'errore che ho ricevuto è stato

"ORA-01000: maximum open cursors exceeded"

Quindi: chiudi sempre il ResultSet!

Devi sempre chiudere tutte le risorse JDBC in modo esplicito. Come già affermato da Aaron e John, la chiusura di una connessione spesso la restituirà solo a un pool e non tutti i driver JDBC vengono implementati esattamente allo stesso modo.

Ecco un metodo di utilità che può essere utilizzato da un blocco 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) {
        }
    }
}

In questo caso Oracle ti darà errori sui cursori aperti.

Secondo: http: //java.sun .com / JavaSE / 6 / docs / api / java / sql / statement.html

sembra che il riutilizzo di una dichiarazione chiuderà tutti i set di risultati aperti e la chiusura di una dichiarazione chiuderà tutti i set di risultati, ma non vedo nulla sulla chiusura di una connessione che chiuderà le risorse che ha creato.

Tutti questi dettagli sono lasciati al provider del driver JDBC.

È sempre più sicuro chiudere tutto esplicitamente. Abbiamo scritto una classe util che racchiude tutto con try {xxx} catch (Throwable {} in modo da poter semplicemente chiamare Utils.close (rs) e Utils.close (stmt), ecc. Senza doversi preoccupare delle eccezioni che si suppone lancino la scansione .

Il ponte ODBC può produrre una perdita di memoria con alcuni driver ODBC.

Se si utilizza un buon driver JDBC, non si dovrebbero avere problemi con la chiusura della connessione. Ma ci sono 2 problemi:

  • Sai se hai un buon pilota?
  • Utilizzerai altri driver JDBC in futuro?

Che la migliore pratica è chiudere tutto.

Lavoro in un grande ambiente Web J2EE. Abbiamo diversi database a cui è possibile connettersi in un'unica richiesta. Abbiamo iniziato a ottenere deadlock logici in alcune delle nostre applicazioni. Il problema era che:

  1. L'utente richiederebbe la pagina
  2. Il server si collega al DB 1
  3. Server Seleziona su DB 1
  4. Il server " chiude " connessione al DB 1
  5. Il server si collega al DB 2
  6. un punto morto!

Ciò si è verificato per 2 motivi, abbiamo riscontrato un volume di traffico molto più elevato del normale e le specifiche J2EE per impostazione predefinita non chiudono effettivamente la connessione fino a quando il thread non termina l'esecuzione. Quindi, nell'esempio precedente il passaggio 4 non ha mai effettivamente chiuso la connessione anche se alla fine sono stati chiusi correttamente.

Per risolvere questo problema, è necessario utilizzare i riferimenti alle risorse in web.xml per le connessioni al database e impostare l'ambito della condivisione condivisa su non condivisibile.

Esempio:

<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>

Ho sicuramente riscontrato problemi con i ResultSet non chiusi, e cosa può far male chiuderli continuamente, giusto? L'incertezza della necessità di ricordare di farlo è uno dei motivi migliori per passare a framework che gestiscono questi dettagli per te. Potrebbe non essere fattibile nel tuo ambiente di sviluppo, ma ho avuto molta fortuna usando Spring per gestire le transazioni JPA. I dettagli disordinati di apertura di connessioni, istruzioni, set di risultati e scrittura di blocchi try / catch / finally troppo complicati (con blocchi try / catch nel blocco finally! ) per chiuderli di nuovo scompaiono, lasciando per fare davvero un po 'di lavoro. Consiglio vivamente di migrare verso quel tipo di soluzione.

In Java, le istruzioni (non i set di risultati) sono correlate ai cursori in Oracle. È meglio chiudere le risorse che si aprono poiché potrebbero verificarsi comportamenti imprevisti rispetto alla JVM e alle risorse di sistema.

Inoltre, alcuni framework di pooling JDBC raggruppano istruzioni e connessioni, quindi non chiuderli potrebbe non contrassegnare tali oggetti come liberi nel pool e causare problemi di prestazioni nel framework.

In generale, se esiste un metodo close () o destroy () su un oggetto, c'è un motivo per chiamarlo e ignorarlo viene fatto a proprio rischio e pericolo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top