Gestione dei Pool di Connessioni (Parte II)

Pagina 2 di 2

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 {

...

private Vector freeConnections; // La coda di connessioni libere
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);
}
..


 

Il codice completo

Potete scaricare il codice completo da qui.

 

Riferimenti

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

Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Sara
Hai dubbi su questo articolo?