Dato che non mi sembrava costruttivo lasciare la pillola a metà, ho deciso di completarla fornendo anche una classe che permetta la connessione di un'applicazione Java ad un database utilizzando il bridge JDBC-ODBC.
Questo tipo di connessione, infatti, risulta utile in tutti quei casi dove il reperimento di un driver JDBC sia difficile o impossibile. Inoltre, questo metodo di connessione permette l'accesso ai database single-file (come sono, ad esempio, i database Microsoft Access).
La classe qui di seguito offre, come nel precedente caso, i metodi per il reperimento dei record (esecuzione query SELECT) e di aggiornamento (esecuzione query UPDATE); un set minimale anche in questo caso, che può essere ampliato a piacere.
Vediamo il codice e, successivamente, spieghiamo come funziona e quali sono le caratteristiche che offre:
codice:
/*
* Classe dedicata alla gestione del Database.
* Gestisce l'apertura e la chiusura della connessione col Database
* Fornisce i metodi per l'esecuzione delle query sul Database
*/
import java.sql.*;
import java.util.Vector;
public class ODBCDatabase {
private String nomeDSN; // Nome DSN dell'origine dati ODBC
private String[][] attributi; // Insieme di attributi da usare per la connessione
private String errore; // Stringa contenente un eventuale messaggio di errore
private Connection db; // Oggetto che rappresenta la connessione col DB
private boolean connesso; // Flag che indica se il DB è connesso o meno
public ODBCDatabase(String nomeDSN) {
this.nomeDSN = nomeDSN;
attributi = new String[0][0];
connesso = false;
}
public ODBCDatabase(String nomeDSN, String [][] attributi) {
this.nomeDSN = nomeDSN;
this.attributi = attributi;
connesso = false;
}
public boolean connetti() {
connesso = false;
try {
// Carico il bridge JDBC-ODBC per la connessione con il database
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String conString = "jdbc:odbc:" + nomeDSN; // Il nome del DSN può anche essere vuoto!!
// Controllo se ci sono attributi ausiliari da usare per la connessione
if (attributi.length > 0) {
// Uso gli attributi per la connessione
for (int i=0; i<attributi.length; i++) {
conString += ";" + attributi[i][0] + "=" + attributi[i][1];
}
}
// Effettuo la connessione
db = DriverManager.getConnection( conString );
// La connessione è avvenuta con successo
connesso = true;
} catch (Exception e) { errore = e.getMessage(); }
return connesso;
}
// Esegue una query di selezione dati sul Database
// query: una stringa che rappresenta un'istruzione SQL di tipo SELECT da eseguire
// colonne: il numero di colonne di cui sarà composta la tupla del risultato
// ritorna un Vector contenente tutte le tuple del risultato
public Vector eseguiQuery(String query) {
Vector v = null;
String [] record;
int colonne = 0;
try {
Statement stmt = db.createStatement(); // Creo lo Statement per l'esecuzione della query
ResultSet rs = stmt.executeQuery(query); // Ottengo il ResultSet dell'esecuzione della query
v = new Vector();
ResultSetMetaData rsmd = rs.getMetaData();
colonne = rsmd.getColumnCount();
while(rs.next()) { // Creo il vettore risultato scorrendo tutto il ResultSet
record = new String[colonne];
for (int i=0; i<colonne; i++) record[i] = rs.getString(i+1);
v.add( (String[]) record.clone() );
}
rs.close(); // Chiudo il ResultSet
stmt.close(); // Chiudo lo Statement
} catch (Exception e) { e.printStackTrace(); errore = e.getMessage(); }
return v;
}
// Esegue una query di aggiornamento sul Database
// query: una stringa che rappresenta un'istuzione SQL di tipo UPDATE da eseguire
// ritorna TRUE se l'esecuzione è adata a buon fine, FALSE se c'è stata un'eccezione
public boolean eseguiAggiornamento(String query) {
int numero = 0;
boolean risultato = false;
try {
Statement stmt = db.createStatement();
numero = stmt.executeUpdate(query);
risultato = true;
stmt.close();
} catch (Exception e) {
e.printStackTrace();
errore = e.getMessage();
risultato = false;
}
return risultato;
}
// Chiude la connessione con il Database
public void disconnetti() {
try {
db.close();
connesso = false;
} catch (Exception e) { e.printStackTrace(); }
}
public boolean isConnesso() { return connesso; } // Ritorna TRUE se la connessione con il Database è attiva
public String getErrore() { return errore; } // Ritorna il messaggio d'errore dell'ultima eccezione sollevata
}
Cominciamo, innanzitutto, a trattare i 2 costruttori: il primo prende un solo parametro stringa che rappresenta il nome del DSN a cui agganciarsi (può anche essere la stringa vuota, ma non ha molto senso in questo caso...), mentre il secondo prende due parametri; il primo rappresenta sempre il DSN che fa riferimento all'origine dati ODBC a cui collegarsi (e anche in questo caso può essere vuota, che ha più senso di prima ), mentre il secondo parametro è una matrice di stringhe, che rappresenta tutti i parametri da passare al DSN. Questa matrice ha il seguente schema
codice:
|-------------|------------|
| PARAMETRO_1 | VALORE_1 |
|-------------|------------|
| PARAMETRO_2 | VALORE_2 |
|-------------|------------|
| ... | ... |
|-------------|------------|
| PARAMETRO_N | VALORE_N |
|-------------|------------|
con la seguente semantica:
codice:
PARAMETRO_1=VALORE_1
PARAMETRO_2=VALORE_2
...
PARAMETRO_N=VALORE_N
Il DSN ODBC, infatti, prevede una stringa di connessione di questo tipo:
codice:
jdbc:odbc:nomeDSN;
PARAMETRO_1=VALORE1;
PARAMETRO_2=VALORE_2;
...;
PARAMETRO_N=VALORE_N
e la classe si occupa, automaticamente, di costruire tale stringa in base ai valori passati dall'utente. In questo modo si ha a portata di mano tutta la maneggevolezza di Java applicata a tutte le potenzialità di ODBC.
I metodi eseguiQuery() e eseguiAggiornamento(), come prima, permettono di eseguire una query di interrogazione ricevendo un Vector contenente tutti i record sottoforma di array di stringhe e di effettuare un aggiornamento ricevendo un valore booleano che indica l'andata a buon fine dell'operazione.
Vediamo un semplice esempio di utilizzo di questa classe per collegarsi ad un database Microsoft Access, il cui file si chiama "MioDatabase.MDB" posizionato nella cartella denominata "MiaCartella", all'interno della cartella dove gira l'applicazione:
codice:
String [][] parametri = {{"DRIVER", "Microsoft Access Driver (*.mdb)"},
{"DBQ", ".\\MiaCartella\\MioDatabase.MDB"}
};
ODBCDatabase db = new ODBCDatabase("", parametri); // Nota: il nome DSN è vuoto!
// Effettuiamo la connessione:
if ( !db.connetti() ) {
System.out.println("Errore durante la connessione!");
System.out.println( db.getErrore() );
System.exit(0);
}
// Reperiamo i dati attraverso una query. Nome della tabella: Tbl.
Vector v = db.eseguiQuery("SELECT * FROM Tbl;");
// Stampiamo i risultati:
int i=0;
while ( i<v.size() ) {
System.out.println("Record numero " + (i+1));
String [] record = (String[]) v.elementAt(i);
for (int j=0; j<record.length; j++)
System.out.println( record[j] );
}
// Eseguiamo un'aggiornamento sulla tabella Tbl:
if ( !db.eseguiAggiornamento("UPDATE Tbl SET campo=valore WHERE campo>1;") ) {
System.out.println("Errore nell'aggiornamento!");
System.out.println( db.getErrore() );
}
// Chiudiamo la connessione col database:
db.disconnetti();
Anche in questo caso è possibile aggiungere alla classe i metodi per il reperimento dei Metadati dal DB, per l'utilizzo delle Prepared Statement o qualsiasi altra aggiunta necessaria.
Ciao.