[GUIDA JAVA - MEDIO/AVANZATO] GESTIRE UN POOL DI CONNESSIONI

[GUIDA JAVA - MEDIO/AVANZATO] GESTIRE UN POOL DI CONNESSIONI

Programmazione - Desktop Application

Valutazione attuale: / 1
ScarsoOttimo 

Riferimenti dell'articolo: pool in java
E' possibile scaricare il codice sorgente di esempio diretamente dal sito Codice di Esempio

Durante lo sviluppo di applicazioni che accedono ad una base di dati, vi sar? capitato di notare che stabilire la connessione verso il database pu? richiedere anche qualche secondo.

Si tratta di un problema rilevante quando si ha a che fare con la progettazione di un sito web, le cui pagine sono costruite dinamicamente accedendo ai dati contenuti in un database.
In questo articolo vedremo come superare l'ostacolo.

Problemi di performance durante l'accesso ai database

Stabilire una connessione con una base di dati ? un'operazione molto complessa. Infatti, ? necessario caricare il driver del database, stabilire una comunicazione bidirezionale sicura fra l'applicazione che deve accedere ai dati e il database stesso, eseguire una procedura di autenticazione e allocare le risorse necessarie per gestire le query successive.

Queste operazioni sono spesso nascoste all'occhio dello sviluppatore che stabilisce la connessione con una o due chiamate di funzione. L'esecuzione di questa procedura ? molto onerosa e richiede alcuni secondi per essere portata a termine.

Questo tempo ? del tutto trascurabile nel caso di un'applicazione stand-alone che spesso viene mantenuta in esecuzione per tempi molto lunghi.
Nel caso di un'applicazione web le cose cambiano: lo scopo infatti ? quello di gestire una singola richiesta, accedere al database e dare la risposta nel tempo minore possibile. Se per ogni richiesta non fosse necessario stabilire una nuova connessione verso il database, i tempi di risposta ne risulterebbero significativamente migliorati; inoltre il server sarebbe meno sottoposto a problemi di sovraccarico, potendo cos? gestire un maggior numero di visitatori.

La soluzione? Un pool di connessioni! Esiste una soluzione elegante per ridurre i tempi di connessione al database nel contesto che ? stato descritto precedentemente: ? sufficiente che il client inserisca la connessione in una cache invece di chiuderla quando siano terminata l'esecuzione di tutte le query.

Un altro processo che debba accedere alla base di dati pu? in tal caso prelevare una connessione esistente dalla cache invece di stabilirne una nuova.

Come ? fatto un pool di connessioni?

Ora analizziamo una struttura dati ed una serie di funzioni minimali che ci permettano di gestire un pool di connessioni.
Per gestire le connessioni disponibili, la struttura dati migliore ? una coda. In tal caso quando un processo deve accedere al database otterr?, prelevandola dalla coda, la connessione pi? vecchia fra quelle in cache, minimizzando la possibilit? di caduta per le onnessioni inutilizzate da troppo tempo.
Se non ci sono connessioni disponibili, il pool deve essere in grado di stabilirne una nuova. Pertanto deve avere a sua disposizione tutte le informazioni per farlo: generalmente si tratta di conoscere il driver, il login, la password di accesso e il nome del database.

In base a quanto detto sopra, il codice che gestisce un pool deve contenere almeno tre funzioni:
getConnection per ottenere una nuova connessione prelevandola dalla coda o creandone una nuova se necessario;
releaseConnection per liberare una connessione gi? utilizzata e garantirne il riutilizzo da parte di altri processi, inserendola nella coda delle connessioni disponibili; inoltre poich? se getConnection non trova nessuna connessione disponibile nella coda deve stabilirne una nuova, ? necessario aggiungere la funzione newConnection che sia in grado di farlo quando richiesto.

Sviluppo passo passo di una classe ConnectionPool in Java

Procediamo con lo sviluppo di codice Java in grado di gestire correttamente un pool di connessioni.
Costruiamo innanzitutto una classe ConnectionPoolException, le cui istanze sono le eccezioni che verranno sollevate quando si dovesse presentare un errore a runtime nella classe ConnectionPool.

// Classe che gestisce le eccezioni sollevate a runtime dalla classe ConnectionPool
public class ConnectionPoolException extends
Exception {
public ConnectionPoolException() {
}
}


Ricordiamo che al pool di connessioni dovranno accedere processi distinti. E' necessatio quindi trovare un artificio per far si che tutti i processi accedano ad unica istanza della classe ConnectionPool.
L'idea ? quella di avere una variabile statica connectionPool all'interno della classe ConnectionPool.
Un metodo statico, getConnectionPool, permetter? di accedere a questa variabile da parte dei processi che ne fanno richiesta. Se la variabile non ? stata ancora istanziata il metodo getConnectionPool provveder? alla sua istanziazione.

Dal momento che pi? processi accedono a getConnectionPool in concorrenza, definiamo il metodo come synchronized.

... // La classe che gestisce un pool di connessioni
public class ConnectionPool {}
... // La variabile che gestisce l'unica istanza di ConnectionPool private static ConnectionPool connectionPool = null;
...

public static synchronized ConnectionPool
getConnectionPool()
throws ConnectionPoolException {
if(connectionPool == null) {
connectionPool = new ConnectionPool();
}
return connectionPool;
}
... }


Il codice di getConnectionPool accede al costruttore della classe per creare l'unica istanza di ConnectionPool. Questo si preoccupa di creare la coda per le connessioni libere, caricare i parametri per l'accesso al database accedendo al metodo loadParameters e caricare il driver della base di dati con il metodo loadDriver.
Osserviamo che il costruttore ? privato. In questo modo garantiamo che l'accesso ad esso avvenga solo tramite la funzione pubblica getConnectionPool.

import java.util.*;
... // La classe che gestisce un pool di connessioni public class ConnectionPool {
... // La coda di connessioni libere private Vector freeConnections;
private String dbUrl; // Il nome del database
private String dbDriver; // Il driver del database
private String dbLogin; // Il login per il database
private String dbPassword; // La password di accesso al database
...

// Costruttore della classe ConnectionPool
private ConnectionPool() throws
ConnectionPoolException {
// Costruisce la coda delle connessioni libere
freeConnections = new Vector();

// Carica I parametric per l'accesso alla base di dati
loadParameters();
// Carica il driver del database
loadDriver();
}
// Funzione privata che carica i parametri per l'accesso al database
private loadParameters() {
// Url per un database locale
dbUrl = "jdbc:mysql://localhost/prova";
// Driver per database mysql
dbDriver = "org.gjt.mm.mysql.Driver";
// Login della base di dati
dbLogin = "Login";
// Password per l'accesso al database
dbPassword = "Password";
}
// Funzione privata che carica il driver per l'accesso al database.
// In caso di errore durante il caricamento del driver solleva un'eccezione.
private loadDriver() throws ConnectionPoolException
{
try {
java.lang.Class.forName(
dbDriver + "?user=" +
dbUser + "&password=" +
dbPassword);
} catch (Exception e) {
throw new ConnectionPoolException();
}
}
... }


Analizziamo la funzione getConnection che restituisce una connessione libera. getConnection verifica innanzitutto che ci siano elementi nella coda delle connessioni libere.
Se la coda non ? vuota, preleva la prima connessione e verifica che sia valida. Se la connessione non ? pi? valida effettua una chiamata ricorsiva per prelevare l'elemento successivo.

Se la coda e' vuota, getConnection chiama newConnection per stabilire una nuova connessione.
Il metodo getConnection ? di tipo synchronized perch? pu? essere richiamato da pi? processi concorrenti.

Il metodo newConnection non deve necessariamente essere synchronized perch? viene richiamato da getConnection che gi? opera in mutua esclusione. import java.sql.*;
... // Il metodo getConnection restituisce una connessione libera prelevandola dalla coda freeConnections oppure se non ci sono connessioni disponibili creandone una nuova con una chiamata a newConnection.....
public synchronized Connection getConnection()
throws ConnectionPoolException {

Connection con;
if(freeConnections.size() > 0) {
// Se la coda delle connessioni libere non ? vuota
// preleva il primo elemento e lo rimuove dalla coda
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
// Verifica se la connessione non ? pi? valida
if(con.isClosed()) {
// Richiama getConnection ricorsivamente
con = getConnection();
}
} catch(SQLException e) {
// Se c'? un errore richiama GetConnection ricorsivamente
con = getConnection();
}
} else {
// se la coda delle connessioni libere ? vuota crea una nuova connessione
con = newConnection();
}
// restituisce la connessione
return con;
}
// Il metodo newConnection restituisce una nuova connessione
private Connection newConnection() throws
ConnectionPoolException {
Connection con = null;
try {
// crea la connessione
con = DriverManager.getConnection(dbUrl);
} catch(SQLException e) {
// in caso di errore solleva un'eccezione
throw new ConnectionPoolException();
}
// restituisce la nuova connessione
return con;
}
...

Una volta terminato l'uso della connessione si chiama il metodo releaseConnection per ritornare la connessione non pi? utilizzata nella coda.
Questo metodo come getConnection opera in regime di concorrenza e deve quindi essere synchronized.

... // Il metodo releaseConnection rilascia una connessione inserendola nella coda delle connessioni libere....
public synchronized void
releaseConnection(Connection con) {
// Inserisce la connessione nella coda
freeConnections.add(con);
}


Infine riportiamo alcuni riferimento utili:

Accesso ai database da java: Java database e programmazione client/server - Giuseppe Naccarato - Apogeo Java 2 Tecniche avanzate - Cay S. Horstmann e Gary Cornwell - McGraw Hill

Tecniche per gestire eccezioni e per la programmazione concorrente: Java la guida completa - Patrick Naughton e Herbert Schildt - Mc Graw Hill Core Java - Gary Cornell e Cay S. Horstmann - Sunsoft Press Java Fondamenti di programmazione - Deitel & Deitel - Apogeo

Sviluppo di siti web dinamici tramite servlet: Java Servlet Programmino - Jason Hunter e Williiam Crawford - O'Reilly

Accesso a database MySql da codice Java: JSP Servlet e MySql - David Harms - McGraw Hill


Alcune note sull'autore:
Davide Lorenzo Marino (che ringraziamo per questa guida chiara e a), e' esperto di programmazione Java, Visual Basic, C/C++, Pascal, Perl ed altri linguaggi piu' o meno noti.

Commenti (0)Add Comment

Scrivi commento
Si deve essere connessi al sito per poter inserire un commento. Registratevi se non avete ancora un account.

busy

Utenti Connessi

0 utenti e 30 ospiti online

Creative Commons License
Questo/a opera è pubblicato sotto una Licenza Creative Commons.