Accesso a database tramite JDBC

di Claudio De Sio Cesari


-Scenario

La tecnologia Java offre indubbiamente tanti vantaggi. Tra questi c'è sicuramente l'interfaccia JDBC che da qualche anno sfida "sfrontatamente" uno standard affermato come ODBC. JDBC infatti, permette alla stessa applicazione di accedere senza modifiche a diversi RDBMS. Ciò implica l'aggiunta ad un'applicazione Java, di per sé indipendente dalla piattaforma, anche l'indipendenza dal database engine. Caliamoci in uno scenario: supponiamo che una società crei un'applicazione Java che utilizza un RDBMS come DB2, lo storico prodotto della IBM. La stessa applicazione gira su diverse piattaforme come server Solaris e client Windows e Linux. Ad un certo punto, per strategie aziendali, i responsabili decidono di sostituire DB2, con un altro RDBMS questa volta di natura free: MySQL. A questo punto, l'unico sforzo da fare, è far migrare i dati da DB2 a MySQL, ma l'applicazione Java, continuerà a funzionare come prima...

-Definizione

JDBC viene spesso inteso come l'acronimo di Java Database Connectivity, anche se la Sun Microsystems non ha mai confermato tale corrispondenza. Si tratta di uno strato di astrazione software tra un'applicazione Java ed un database. La sua struttura a due livelli, permette di accedere a database engine differenti, a patto che questi supportino l'ANSI SQL 2 [1]. I due fondamentali componenti di JDBC sono:

  1. Un'implementazione del vendor del RDBMS (o di terze parti) conforme alle specifiche delle API java.sql.

  2. Un'implementazione da parte dello sviluppatore dell'applicazione.

-Implementazione del vendor (Driver JDBC)

Il vendor deve fornire l'implementazione di una serie di interfacce definite dal package java.sql, ovvero Driver, Connection, Statement, PreparedStatement, CallableStatement, ResultSet, DatabaseMetaData, ResultSetMetaData. Ciò significa che saranno fornite alcune classi magari impacchettate in un unico file archivio jar, che implementano i metodi delle interfacce appena citate. Solitamente tali classi appartengono a package specifici, ed i loro nomi sono spesso del tipo nomeDBnomeInterfacciaImplementata (per esempio: DB2Driver, DB2Connection...). Inoltre il vendor dovrebbe fornire allo sviluppatore anche una minima documentazione. Attualmente tutti i più importanti database engine, supportano driver JDBC [2].

-Implementazione dello sviluppatore (Applicazione JDBC)

Lo sviluppatore ha un compito piuttosto semplice: implementare del codice che sfrutta l'implementazione del vendor, seguendo pochi semplici passi. Un'applicazione JDBC deve:

  1. Caricare un driver

  2. Aprire una connessione con il database

  3. Creare un oggetto Statement per interrogare il database

  4. Interagire con il database

  5. Gestire i risultati ottenuti

Il lettore si stupirà della semplicità e la potenza con cui verranno eseguiti tali passi studiando l'esempio che segue.

-Esempio di applicazione JDBC

Viene presentato di seguito una semplice applicazione che interroga un database. Viene sfruttato come driver l'implementazione della Sun del jdbc-odbc bridge, presente nella libreria standard di Java (JDK1.1 in poi):

0   import java.sql.*;
1
2
  public class JDBCApp {
3
    public static void main (String args[]) {
4
      try {
5 // Carichiamo un driver di tipo 1 (bridge jdbc-odbc)
6
        String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
7         Class.forName(driver);
8 // Creiamo la stringa di connessione
9         String url = "jdbc:odbc:myDataSource";
10 // Otteniamo una connessione con username e password
11        Connection con =
12        DriverManager.getConnection (url, "myUserName", "myPassword");
13 // Creiamo un oggetto Statement per poter interrogare il db
14        Statement cmd = con.createStatement ();
15 // Eseguiamo una query e immagazziniamone i risultati
16 // in un oggetto ResultSet
17        String qry = "SELECT * FROM myTable";
18        ResultSet res = cmd.executeQuery(qry);
19 // Stampiamone i risultati riga per riga
20        while (res.next()) {
21        System.out.println(res.getString("columnName1"));
22        System.out.println(res.getString("columnName2"));
23      }
24      res.close();
25      cmd.close();
26      con.close();
27    } catch (SQLException e) {
28         e.printStackTrace();
29    } catch (ClassNotFoundException e) {
30         e.printStackTrace();
31       }
32    }
33  }


-Analisi dell'esempio JDBCApp

La nostra applicazione è costituita da un'unica classe contenente il metodo main, non perché sia la soluzione migliore, bensì per evidenziare la sequenzialità delle azioni da eseguire (Clicka qui per un sequence diagram).
Alla riga 0, viene importato l'intero package
java.sql, per poter utilizzare i reference relativi alle interfacce definito in esso, e sfruttando il polimorfismo utilizzarli per puntare ad oggetti istanziati dalle classi che implementano tali interfacce, ovvero, le classi che sono fornite dal vendor. In questo modo l'applicazione non nominerà mai all'interno il nome di una classe fornita dal vendor, rendendo in questo modo l'applicazione indipendente dal database utilizzato. Infatti, gli unici riferimenti espliciti all'implementazione del vendor risiedono all'interno di stringhe, che sono ovviamente facilmente parametrizzabili in svariati modi.
Alla riga 7, utilizziamo il metodo statico
forName() della classe Class (package java.lang) per caricare in memoria l'implementazione del driver JDBC, il cui nome completo viene specificato nella stringa argomento di tale metodo. A questo punto il driver è caricato in memoria e si auto-registra con il DriverManager grazie ad un inizializzatore statico, anche se questo processo è assolutamente trasparente allo sviluppatore.
Tra la riga 9 e la riga 12 viene aperta una connessione al database mediante la definizione di una stringa
url, che deve essere disponibile nella documentazione fornita dal vendor (che però ha sempre una struttura del tipo jdbc:subProtocol:subName), e la chiamata al metodo statico getConnection() sulla class DriverManager.
Alla riga 14 viene creato un oggetto
Statement che servirà da involucro per trasportare le eventuali interrogazioni o aggiornamenti al database.
Tra la riga 17 e la riga 18 viene formattata una query SQL in una stringa chiamata
qry, eseguita sul database, ed immagazzinati i risultati all'interno di un oggetto ResultSet. Quest'ultimo corrisponde ad una tabella formata da righe e colonne dove è possibile estrarre risultati facendo scorrere un puntatore tra le varie righe mediante il metodo next().
Infatti tra la riga 20 e 23, un ciclo while chiama ripetutamente il metodo next(), il quale restituirà false se non esiste una riga successiva a cui accedere. Quindi, fin quando ci sono righe da esplorare vengono stampati a video i risultati presenti alle colonne di nome columnName1 e columnName2.
Tra la riga 24 e la riga 26 vengono chiusi il ResultSet res, lo Statement cmd, e la Connection con.
Tra la riga 27 e la riga 31 vengono gestite le eccezioni
SQLException (lanciabile da qualsiasi problema con JDBC, da una connessione non possibile, ad una query SQL errata) e ClassNotFoundException (lanciabile nel caso fallisca il caricamento del driver mediante il metodo forName())
NB: Per poter utilizzare quest'applicazione bisogna disporre di una fonte dati ODBC installata per il database che si vuole utilizzare (solo se si utilizza un driver del tipo bridge jdbc-odbc), e sostituire alcune stringhe così come esposto nella nota [3].

-Conclusioni

L'argomento JDBC è tanto potente quanto facile da implementare. Si consiglia al lettore che voglia approfondire le sue conoscenze, la consultazione della documentazione della libreria standard ed in particolare dei package java.sql e javax.sql (JDK 1.4 in poi). Esiste anche un breve tutorial nella documentazione stessa ed altri sul sito http://java.sun.com/products/jdbc/index.html. Infatti, JDBC offre supporto anche alle stored procedure, alle transazioni, alle connection pool, ed altre caratteristiche avanzate per l'accesso ai database, come al solito con la classiche caratteristiche della tecnologia Java: sicurezza, semplicità, robustezza, indipendenza dalla piattaforma...


NOTE

  1. La stragrande maggioranza dei database engine in circolazione supporta come linguaggio di interrogazione un soprainsieme dell'ANSI SQL 2. Ciò significa che esistono comandi che funzionano specificamente solo sui RDBMS su cui sono stati definiti (comandi proprietari) e che non sono parte dell'SQL standard. Questi comandi, semplificano l'interazione tra l'utente e il database, sostituendosi a comandi SQL standard più complessi. Ciò implica che è sempre possibile sostituire ad un comando proprietario del RDBMS utilizzato con un comando SQL standard, anche se più complesso. Un'applicazione Java-JDBC, che vuole mantenere una completa indipendenza dal database engine deve utilizzare solo comandi SQL standard, oppure prevedere appositi controlli lì dove si vuole per forza adoperare un comando proprietario. [torna indietro]

  2. Esistono quattro tipologie diverse di driver JDBC caratterizzati da differenti potenzialità e strutture, per una lista aggiornata dei driver disponibili http://java.sun.com/products/jdbc/jdbc.drivers.html . [torna indietro]

  3. Riga 6: è possibile assegnare alla stringa driver il nome di un altro driver disponibile (opzionale)
    Riga 9: è possibile assegnare alla stringa url il nome di un'altra stringa di connessione (dipende dal driver JDBC del database utilizzato e si legge dalla documentazione del driver). Nel nostro caso, disponendo di una fonte dati (data source) ODBC installata, basta sostituire il nome nella stringa il nome myDataSource con quello della fonte dati.
    Riga 12: è possibile sostituire le stringhe myUserName e my Password rispettivamente con la username e la password per accedere alla fonte dei dati. Se non esistono username e password per la fonte dati in questione, basterà utilizzare il metodo DriverManager.getConnection(url).
    Riga 17: sostituire nella stringa myTable con il nome di una tabella valida
    Righe 21 e 22: sostituire le stringhe columnName1 e columnName2 con nomi di colonne valide per la tabella in questione. [torna indietro]



HOME

CONTATTI