JDBC (avanzato) Supporto alle transazioni Connection Pool try { GESTIRE TRANSAZIONI con.setAutoCommit(false); Statement st=con.createStatement(); st.executeUpdate(“…”); st.executeUpdate(“…”); … con.commit(); } catch (Exception ex) { try { con.rollback();} catch (SQLException sqx) } 1 Gestire connessioni in modo efficiente • Capita spesso di ricevere molte richieste di pochi dati da parte di molti utenti – Server Web di interfaccia ai dati • La soluzione vista prima non è efficiente – Creare e rilasciare una connessione è costoso • La soluzione è un gestore che mantiene vivo un set di connessioni e via via le alloca agli “utenti” – Pattern: Connection Pool Semplice implementazione in Java CONNECTION POOL import java.sql.*; public class MyConnectionPool { // array di connessioni al database Connection con[]; // array delle disponibilità delle connessioni boolean busy[]; // registra chi sta tenendo occupata la connessione String who[]; // numero di connessioni attive int numCon; // incremento dimensione del pool per accogliere nuove richieste int inc; 2 // parametri di accesso al database String dbUrl; String dbUsername; String dbPswd; String driverString; /** Costruttore */ public MyConnectionPool ( String dbUrl, String dbUsername, String dbPswd, int numCon, int inc, String driverString ) throws Exception { this.dbUrl = dbUrl; this.dbUsername = dbUsername; this.dbPswd = dbPswd; this.numCon = numCon; this.inc = inc; this.driverString = driverString; newConnections(); } /** * newConnections */ private synchronized void newConnections() throws Exception { // alloca gli array globali (connessioni e info) con = new Connection[numCon]; busy = new boolean[numCon]; who = new String[numCon]; Class.forName(driverString); for (int i = 0; i < numCon; i++) { con[i] = DriverManager.getConnection(dbUrl,dbUsername,dbPswd); busy[i] = false; who[i] = ""; } } 3 /** * extendConnections */ public synchronized void extendConnections() throws Exception { // copia dei vecchi vettori Connection con2[] = con; boolean busy2[] = busy; String who2[] = who; // creazione dei nuovi vettori estesi con = new Connection[numCon+inc]; busy = new boolean[numCon+inc]; who = new String[numCon+inc]; //ciclo per trasferire le vecchie connessioni nei nuovi array for (int i = 0; i < numCon; i++) { con[i] = con2[i]; busy[i] = busy2[i]; who[i] = who2[i]; } //ciclo per creare le nuove connessioni da aggiungere alle precedenti for (int i = numCon; i < numCon+inc; i++) { con[i] = DriverManager.getConnection(dbUrl,dbUsername,dbPswd); busy[i] = false; who[i] = ""; } numCon += inc; } 4 /** getConnection - assegna una connessione all’utente who */ public synchronized Connection getConnection(String who) throws Exception { int indFree = findFreeConnection(); if (indFree >= 0) { busy[indFree] = true; who[indFree] = who; return con[indFree]; } // se arriva qui, il pool è saturo: lo estende e richiama findFreeConn…() extendConnections(); indFree = findFreeConnection(); if (indFree >= 0) { busy[indFree] = true; who[indFree] = "No name"; return con[indFree]; } return null; // se arriva qui non ci sono proprio più risorse di calcolo } /** getConnection */ public synchronized Connection getConnection() throws Exception { return getConnection(“noName”); } /** * releaseConnection - la connessione viene solo “liberata” */ public synchronized void releaseConnection(Connection c) { for (int i = 0; i < numCon; i++) { if (con[i] == c) { who[i] = ""; busy[i] = false; } } } 5 /** findFreeConnection - scandisce il vettore e restituisce l’indice */ protected int findFreeConnection() { for(int i = 0; i < numCon; i++) if ( ! busy[i] ) return i; return -1; } /** printStatusConnection */ public String printStatusConnection() { String result = ""; for (int i = 0; i < numCon; i++) result += "Conn. " + i + ": " + busy[i] + " used by: " + who[i]; return result; } } // chiude la classe 6