ResultSet non chiuso quando la connessione è chiusa?

Ho eseguito 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 incontrato lo schema sopra descritto in molti progetti (da un bel po ‘di aziende) e nessuno stava chiudendo ResultSet o Statements.

Hai avuto problemi con ResultSet e le istruzioni non vengono chiuse quando la connessione è chiusa?

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

    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, la connection.close() rimetterebbe la connessione nel pool. Inoltre, alcuni database dispongono di una risorsa cursore sul server che non verrà liberata correttamente, a meno che non venga chiusa esplicitamente.

    Ho avuto problemi con ResultSet non chiusi in Oracle, anche se la connessione è stata chiusa. L’errore che ho avuto è stato

     "ORA-01000: maximum open cursors exceeded" 

    Quindi: chiudi sempre il tuo ResultSet!

    È necessario chiudere sempre tutte le risorse JDBC in modo esplicito. Come già detto da Aaron e John, chiudere una connessione spesso lo restituisce 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 finale:

     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) { } } } 

    Oracle ti darà errori riguardo i cursori aperti in questo caso.

    Secondo: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

    sembra che riutilizzare una dichiarazione chiuderà tutti i gruppi di risultati aperti, e la chiusura di un’istruzione chiuderà qualsiasi gruppo di risultati, ma non vedo nulla sulla chiusura di una connessione chiuderà nessuna delle risorse che ha creato.

    Tutti questi dettagli sono lasciati al fornitore del driver JDBC.

    È sempre più sicuro chiudere tutto in modo esplicito. Abbiamo scritto una class util che racchiude tutto con try {xxx} catch (Throwable {} in modo che tu possa semplicemente chiamare Utils.close (rs) e Utils.close (stmt), ecc senza doversi preoccupare delle eccezioni che chiudere la scansione apparentemente buttano .

    L’ODBC Bridge 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 guidatore?
    • Utilizzerai altri driver JDBC in futuro?

    Che la pratica migliore è chiudere tutto.

    Lavoro in un grande ambiente web J2EE. Abbiamo diversi database a cui è ansible connettersi in una singola richiesta. Abbiamo iniziato ad avere problemi logici in alcune delle nostre applicazioni. Il problema era che come segue:

    1. L’utente richiede una pagina
    2. Il server si connette a DB 1
    3. Il server seleziona su DB 1
    4. Il server “chiude” la connessione a DB 1
    5. Il server si connette a DB 2
    6. Un punto morto!

    Ciò si è verificato per 2 motivi, abbiamo riscontrato un volume di traffico molto più alto del normale e la specifica J2EE per impostazione predefinita non chiude effettivamente la connessione finché il thread non termina l’esecuzione. Quindi, nel precedente esempio, il passaggio 4 non ha mai effettivamente chiuso la connessione anche se alla fine erano stati chiusi correttamente.

    Per risolvere questo problema, devi utilizzare i riferimenti di risorsa nel web.xml per le tue connessioni di database e devi impostare il res-sharing-scope in unsharable.

    Esempio:

      My Database jdbc/jndi/pathtodatasource javax.sql.DataSource Container Unshareable  

    Ho sicuramente visto problemi con i ResultSet non chiusi, e cosa può fare male chiuderli tutto il tempo, giusto? L’inaffidabilità di dover ricordare di farlo è uno dei migliori motivi per passare a framework che gestiscono questi dettagli per te. Potrebbe non essere fattibile nel tuo ambiente di sviluppo, ma ho avuto la fortuna di utilizzare Spring per gestire le transazioni JPA. I dettagli disordinati delle connessioni di apertura, delle istruzioni, degli insiemi di risultati e della scrittura di complicati blocchi try / catch / finally (con i blocchi try / catch nel blocco finally! ) Per chiuderli di nuovo scompare, lasciandoti fare un po ‘di lavoro . Consiglio vivamente di migrare a quel tipo di soluzione.

    In Java, le istruzioni (non i gruppi di risultati) sono correlate ai cursori in Oracle. È meglio chiudere le risorse che si aprono in quanto può verificarsi un comportamento imprevisto nei confronti della JVM e delle risorse di sistema.

    Inoltre, alcuni pool di pool JDBC raggruppano le istruzioni e le connessioni, quindi non chiuderle 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 object, c’è un motivo per chiamarlo e ignorarlo viene fatto a proprio rischio e pericolo.