Questo sito usa cookie analitici di terze parti, leggi la policy. Continuando ad usare il sito, acconsenti implicitamente all'uso dei cookie.

Menu contestuale


Link pubblicitari laterali


Data ultimo aggiornamento: 30/06/2011

JDBC Best Practice - Gestione delle connessioni - Thinking.it

Le migliori tecniche per gestire Connection, Statement e ResultSet, motivate e descritte con esempi pratici.

Nello sviluppo di applicazioni Java, può capitare di dover gestire l'accesso ad una base dati senza far uso dei moderni framework di persistenza (es.: Hibernate, TopLink, ecc.), usando direttamente le interfacce JDBC.

Questo tipo di approccio, benché offra maggiori gradi di libertà al programmatore, il più delle volte conduce ad un codice errato o poco robusto che, nel migliore dei casi, provoca l'esaurimento delle risorse disponibili ed il conseguente blocco dell'applicazione.

In questo articolo, si descriverà una metodologia di gestione degli oggetti JDBC capace di garantire la corretta allocazione e deallocazione delle risorse di database, sia nelle situazioni normali che in quelle anomale.

Principi e regole generali.

Principi:

  • il costo del lancio di un'eccezione è superiore a quello di un test su una variabile

Regole generali:

  • gli oggetti JDBC devono essere rilasciati dal metodo che li acquisisce, anche in caso d'errore;
  • una transazione JDBC deve essere gestita da un solo thread;

Come gestire in modo robusto ed efficiente una connessione JDBC.

Ipotesi:

  • le connessioni sono acquisite da un pool tramite l'interfaccia javax.sql.DataSource e rilasciate invocando il metodo Connection.close(), che è la tipica situazione di un'applicazione web Java_EE.

Il codice Java riportato di seguito è il risultato dell'applicazione delle regole suddette:

DataSource ds = (il fornitore di connessioni); // le variabili da usare nel finally vengono dichiarate fuori dal blocco try/catch Connection con = null; Statement stmt = null; ResultSet rs = null; try { // acquisisce la connessione all'interno del blocco try/catch in modo // da gestire correttamente i casi di errore. con = ds.getConnection(); // In generale è preferibile non usare l'auto-commit; // di solito il DataSource è configurato per fornire connessioni // già con l'auto-commit disabilitato. con.setAutoCommit(false); stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("una query"); while (rs.next()) { } // rs viene chiuso esplicitamente, anche se non necessario perché // lo Statement stmt viene rieseguito o chiuso. // (utile se si usano driver vecchi che non rispettano le specifiche // e lasciano i cursori aperti... che puntualmente finiscono). // L'assegnazione a null serve solo per evitare di richiamare il close() // nel finally, ma non è necessaria. rs.close(); rs = null; // stmt non viene chiuso, perché riutilizzato sotto. // rs viene sovrascritto, ma il precedente valore, se non fosse stato già // chiuso, dovrebbe essere comunque chiuso automaticamente da executeQuery() rs = stmt.executeQuery("altra query, stesso statement"); while (rs.next()) { } rs.close(); rs = null; stmt.close(); stmt = null; stmt = con.prepareStatement("altra query, altro statement"); rs = stmt.executeQuery(); while (rs.next()) { } rs.close(); rs = null; stmt.close(); stmt = null; // invocato per chiudere la transazione (auto-commit disabilitato) con.commit(); } catch (SQLException sqle) { if (con != null) { try { // invocato per chiudere la transazione con.rollback(); } catch (SQLException sqle2) {} } // non sarebbe necessario loggare l'errore qui se l'eccezione è // gestita al livello superiore, ma così viene mostrata la causa diretta logger.error("error executing transaction: "+sqle.getMessage()); throw new AppException(sqle); } finally { // chiusura del ResultSet (non sempre necessaria, ma utile) if (rs != null) { // i try/catch separati servono ad evitare che un'eventuale nuova // eccezione impedisca il rilascio di stmt e con! // Le catch nel finally sono senza throw per evitare di coprire // l'eventuale eccezione catturata dalla catch più esterna. try { rs.close(); } catch (SQLException sqle) {} rs = null; } // chiusura dello Statement (IMPORTANTE!) // Se non fosse chiuso esplicitamente, lo Statement sarebbe comunque chiuso // dal Garbage Collector, ma sarebbe pericoloso e poco efficiente. if (stmt != null) { try { stmt.close(); } catch (SQLException sqle) {} stmt = null; } // rilascio della connessione (VITALE!) if (con != null) { try { con.close(); } catch (SQLException sqle) { logger.error("error releasing connection: "+sqle.getMessage()); } con = null; } }

(da completare...)


Banner pubblicitario inferiore


Menu a pié di pagina


Statistiche

Pagine totali: 902

Visite totali: 875

Bot: 0

Utenti unici: 0

Utenti on-line: 0

Pagine viste: 0

Permanenza: 00s


Conformità agli standard

  • [XHTML]
  • [CSS]
  • [WAI/WCAG 2.0 AAA]