DriverLayer
e ApplicationLayer
.
Il DriverLayer
è lo strato di JDBC che si occupa dell'interfacciamento con il database mentre l'ApplicationLayer
riguarda le funzionalità che JDBC offre per manipolare dati tramite costrutti Java.
Figura 1
DriverLayer
è essenzialmente composto dall'interfaccia Driver
e dalla classe DriverManager.
Il Driver
è il vero e proprio driver che ci permette il collegamento al database e che richiamiamo nel nostro programma, mentre il DriverManager
gestisce l'instaurazione della connessione con il database e la restituzione della connessione al nostro programma, anche se in molti casi è più conveniente crearsi da soli un proprio DriverManager
per particolari esigenze, come ad esempio pooling di connessioni.
L'ApplicationLayer
, che riguarda appunto più il lato applicativo, è principalmente composto dalle interfacce Connection, Statement, ResultSet, PreparedStatement
edSQLException
. Connection
è quella che modella la connessione al database e serve per creare gli Statement
o i PreparedStatement
che sono i costrutti che ci permettono di eseguire interrogazioni, modifiche e inserimenti verso il database. I PreparedStatement
sono praticamente degli Statement
quasi completi ai quali dobbiamo passare dei parametri, anche a run-time, e quindi migliorano l'efficienza specialmente in programmi ripetitivi. L'oggetto che modella i dati che il database ci restituisce in prima istanza dopo una query è il ResultSet
, mentre l'SQLException
è una semplice classe che estende Exception
e che tramite opportuni metodi ci permette di venire a conoscenza degli errori generati dalla nostra applicazione riguardanti JDBC.
Prima di immergerci in qualche riga di codice dobbiamo parlare dei driver che permettono il collegamento al database. In un primo momento infatti un ingenuo programmatore non riesce bene a capire le sottili differenze dei driver che si trova davanti quando vuole collegare la sua applicazione ad un database. Invece le differenze ci sono e sono importanti. Bisogna prima di tutto dire che esistono 4 diversi tipi di driver JDBC:
DriverManager
. Per caricare il driver usiamo Class.forName
al quale passiamo il nome del driver. Ad esempio il caricamento del driver per Oracle 9i Lite è il seguente:
Class.forName(«oracle.lite.poljdbc.POLJDBCDriver»);
Connection
, tramite il suo metodo getConnection
al quale devo passare come argomento un URI (Uniform Resource Identificator), un login e una password. L'URI è della forma jdbc:<protocollodb>:<parametri>
. Ecco quindi la connessione al database:
String URI = "jdbc:polite:EsempioDb";
// oppure jdbc:polite://127.0.0.1/EsempioDb
String LOGIN = "system";
String PASSWD = "manager";
Connection conn = DriverManager.getConnection(URI, LOGIN, PASSWD);
SQLException
che dovrà quindi essere opportunamente catturata dalla nostra applicazione. SQLException
è utilissimo al programmatore visto che dispone di due metodi che permettono un veloce e semplice determinazione del problema.
Il metodo getErrorCode()
di questa classe restituisce il codice d'errore deciso da chi ha fatto il database, quindi facilmente consultabile, mentre il metodo getSQLState()
restituisce al programmatore una stringa contenente lo «stato» del DB in maniera conforme alle specifiche XOPEN o SQL99 (dipende dal DB), dando comunque al programmatore un semplice diretto messaggio che può portare subito all'individuazione del problema.
A questo punto Java ci offre tre semplici oggetti che semplificano la nostra vita per inviare e ricevere informazioni al database: Statement, PreparedStatement e ResultSet
.
Lo Statement
viene creato attraverso il metodo createStatement()
di Connection
. Ci sono due metodi importanti della classe Statement
e sono executeQuery(String)
ed executeUpdate(String)
. Il primo serve per interrogazioni al database (SELECT) mentre il secondo per inserimenti, aggiornamenti e cancellazioni (INSERT, UPDATE, DELETE).
Il metodo executeQuery(String)
restituisce un ResultSet
, un oggetto-tabella che rappresenta i dati selezionati dalla nostra interrogazione. Poi noi dobbiamo visitare questo ResultSet
per vedere quali sono i dati e utilizzarli nel modo voluto. Questo oggetto viene letto come con un puntatore che grazie al metodo next()
passa alla successiva riga della tabella che abbiamo avuto come risposta. Ecco un esempio di utilizzo:
try{
String URI="jdbc:polite:EsempioDb";
String LOGIN="system";
String PASSWD="manager";
Connection conn=DriverManager.getConnection(URI, LOGIN, PASSWD);
//Creiamo lo Statement necessario per eseguire l'interrogazione che vogliamo
//tramite il metofo executeQuery che ci restituisce una lista di studenti che
//abbiamo nel nostro database
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT NOME,COGNOME,DATA,ETA FROM STUDENTI");
//Utilizziamo il metodo next() del ResultSet per poter scandire man mano
//tutte le righe della tabella che c'è stata restituita. Per ogni riga
//utilizziamo un metodo getXXX dove XXX è il tipo di dato contenuto nel
//database. In questo caso passiamo a questi metodi dei numeri per riferirci
//al numero di colonna della tabella che viene restituita ma potevamo passare
//direttamente anche il nome della stessa.
while (rs.next()) {
System.out.println("Nome "+rs.getString(1));
System.out.println("Cognome "+rs.getString(2));
System.out.println("Data Di Nascita "+rs.getDate(3));
System.out.println("Età "+rs.getInt(4));
System.out.println("- - - - - - - - -");
}
}
catch(SQLException e) {
//Abbiamo catturato un eccezione generata dalle istruzioni precedenti e
//scriviamo a schermo il contenuto dell'eccezione, che in caso di errore
//logico relativo al database ci restituirà l'errore che ci restituisce il
//database.
System.out.println(e.getMessage());
}
finally{
//Cerchiamo, qualsiasi sia stato l'errore, di chiudere lo statement e la
//connessione
try{
stat.close();
conn.close();
}
catch(SQLException ex)
{System.out.println(ex.getMessage());}
}
PreparedStatement
. Facciamo un esempio, invece di scrivere 50 volte la query per l'update di 50 studenti nel database la scrivo una volta e poi le passo di volta in volta che voglio inserire dei nuovi studenti dei parametri:
// I punti interrogativi sono i valori che saranno conosciuti a runtime
// dall'applicazione
PreparedStatement ps=conn.prepareStatement(
"UPDATE STUDENTI SET MEDIA=? WHERE NOME=?");
// Immaginiamo di avere un vettore V con i valori da aggiornare che
// scorriamo fino alla fine
int i=0;
while (!V.isEmpty()) {
// setto a 22 il valore MEDIA
ps.setInt(1,(int)V.get(i));
// setto uguale a Luca il valore di NOME
ps.setString(2,(String)V.get(i+1));
// Niente parametri per il metodo in questo caso
ps.executeUpdate();
i=i+2;
}