Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java Fondamenti di JDBC Concetto di driver Il dialogo fra applicazione e DBMS non è mai gestito direttamente ma passa in genere per un opportuno modulo software chiamato driver che agisce da interfaccia fra il client e il DBMS (Database Management System) stesso. In “origine” la comunicazione fra applicativo e database era piuttosto difficoltosa: c'era infatti bisogno di un driver specifico, cioè di una API (Application Program Interface) specifica e proprietaria, per poter accedere ad ogni diverso database. Fig. 1 – Situazione alle “origini” ODBC (Open Database Connectivity) Driver Nel 1991, Microsoft progettò Open Database Connectivity (ODBC), una API standard per la connessione ai DBMS. In tal modo, i programmi, attraverso questo strato software comune, potevano connettersi a diversi tipi di database utilizzando le funzioni standard disponibili nella API e il codice SQL (Structured Query Language). La prima versione è stata sviluppata su Windows in linguaggio C e consiste di una dll (dynamic link library); altre release sono state scritte per Unix, OS/2 e Macintosh. Fig. 2 – Driver ODBC jdbc-parte1.pdf Pag. 1/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java Nella fig. 2 non sono evidenziati i driver proprietari dei singoli database. ODBC genera automaticamente richieste che il sistema di database è in grado di capire. JDBC-ODBC Bridge Successivamente, Sun Microsystems, in attesa di una soluzione “pure Java 100%”, introdusse una API intermedia tra ODBC e l'applicazione denominandola JDBC-ODBC Bridge (tipo 1). Fig. 3 – Driver “ponte” JDBC-ODBC Il driver converte le chiamate ai metodi JDBC-ODBC in chiamate a funzioni ODBC. Il driver è implementato nella classe jdbc.odbc.JdbcOdbcDriver ed è fornito con Java 2 SDK Standard Edition. JDBC Driver JDBC (Java DataBase Connectivity) (tipo 4) è una API per database interamente scritta in java localizzata nel package java.sql. JDBC API fornisce metodi e interfacce per interrogare e modificare i dati ed è Object Oriented. La piattaforma Java 2 Standard Edition contiene le API JDBC, insieme all'implementazione di un bridge JDBC-ODBC, che permette di connettersi a database relazionali che supportano ODBC (per esempio Access). Fig. 4 – Driver JDBC jdbc-parte1.pdf Pag. 2/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java Il problema Vogliamo progettare una applicazione java “console” che ci consenta di ottenere l'elenco dei libri scritti da un certo autore di cui è nota l'anagrafica (nome e cognome). Si tratta di un esempio già trattato in altre esercitazioni, in particolare si veda l'articolo “Database a oggetti: db4o”, l'esercitazione “Prototipo applicazione Biblioteca”, l'articolo “DAO-Data Access Object” reperibili nella sezione Java, http://www.mauriziocozzetto.it. Ipotizziamo che gli autori, i libri e le case editrici debbano essere memorizzati in un database MySQL (biblio_db) e che per semplicità un libro possa essere scritto da un solo autore (nella realtà un libro può essere scritto a più mani), mentre una casa editrice può pubblicare più libri. Il modello dei dati Fig. 5 – Diagramma E-R (Entity-Relationship) Il modello a oggetti La classe DAO (Data Access Object) fungerà da strato software di accesso al database. Le tre classi fondamentali Autore, Libro ed Editore “mapperanno” le tre tabelle autori_tbl, libri_tbl ed editori_tbl. Fig. 6 – Struttura delle classi di base dell'esercitazione jdbc-parte1.pdf Pag. 3/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java Preparazione dell'ambiente di lavoro Xampp (Windows/Linux) Xampp è un ottimo tool che fornisce allo sviluppatore in un unico pacchetto un server web (Apache2) dotato dell'estensione per il Php e un server MySQL, oltre ad altri strumenti come PhpMyAdmin, Mercury (un server di posta) ecc. Possiamo installarlo sia in ambiente Windows che Linux: maggiori dettagli per l'installazione, sono reperibili sul sito http://www.xampp.org. Per attivarlo possiamo usare in ambiente Windows l'apposita icona presente sul Desktop o lanciare il demone (in ambiente Linux Ubuntu) mediante il comando sudo /opt/lampp/lampp start Per arrestare il servizio procediamo in maniera analoga cliccando due volte sull'icona di arresto del servizio (Windows) o mediante il comando sudo /opt/lampp/lampp stop (Linux Ubuntu). In alternativa possiamo sempre decidere di installare e configurare sulla nostra macchina i 3 servizi in maniera distinta, facendo attenzione a configurare correttamente i 3 programmi e l'ambiente di lavoro nel suo complesso. Ricordiamo che una volta attivo, il server Web Apache2 rimane in ascolto sulla porta 80 della nostra macchina e che MySQL rimane invece in ascolto sulla porta 3306. Xampp è ottimo per il test delle applicazioni ma è sconsigliato in produzione (ad esempio MySQL dispone del solo utente root senza password). PhpMyAdmin (Xampp) Prepariamo, usando l'utility PhpMyAdmin, la struttura delle tre tabelle autori_tbl, editori_tbl e libri_tbl (nell'ordine in figura). Fig. 7 – Struttura delle 3 tabelle autori_tbl, editori_tbl e libri_tbl jdbc-parte1.pdf Pag. 4/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java In quest'ultima tabella (libri_tbl) , i campi idAutore e idEditore fungono da chiavi esterne. Inizialmente le tre tabelle libri_tbl, autori_tbl ed editori_tbl non contengono dati. Inseriamo poi alcuni dati di prova usando PhpMyAdmin. I Driver JDBC di MySQL Una volta costruito il database, dobbiamo procurarci i driver nativi Java MySQL, chiamati MySQL Connector/J (http://dev.mysql.com/downloads/connector/j/5.1.html). Dal pacchetto scaricato mysql-connector-java-5.1.6.tar.gz preleviamo il file mysql-connector-java-5.1.6-bin.jar e copiamolo (o spostiamolo) in un package del nostro progetto. Ricordiamo tuttavia che nelle versioni più recenti di NetBeans (ad esempio nella versione 6.1), questi driver sono già installati: occorre solo aggiungerli al progetto (tasto destro del mouse sul progetto > Properties > Libraries > Add Library ... > MySQL JDBC Driver) I driver JDBC-ODBC di Access (Windows) In alternativa a Xampp, possiamo sempre preparare un database in Access e costruire (mediante il Pannello di Controllo > Strumenti di Ammnistrazione > Origine dati JDBC-ODBC > (Scheda DSN) Aggiungi... > DSN (Data Source Name)) un alias che identifica in modo univoco la “fonte dati”. Riepilogo principali metodi e interfacce JDBC Caricamento dei driver // Per un database MySQL String driver = “ com.mysql.jdbc.Driver”; // Il metodo forName forza il caricamento del driver Class.forName(driver); // lancia una ClassNotFoundException // Se il database è Oracle, allora // String driver = “oracle.jdbc.OracleDriver”; // Se il driver è JDBC-ODBC (tipo 1), allora // String driver = “sun.jdbc.odbc.JdbcOdbcDriver”; // Se il database è PostgresQL, allora // String driver = “com.postgresql.Driver”; Creazione della connessione // Per un database MySQL String url = "jdbc:mysql://localhost:3306/biblio_db”; // Xampp non definisce una password per l'utente root // si consiglia di impostare una password in produzione String username=”root”; String password = “”; jdbc-parte1.pdf Pag. 5/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java // Connection è un'interfaccia, getConnection() un metodo statico della classe DriverManager Connection conn = DriverManager.getConnection(url, username, password); // lancia una SQLException // username e password sono opzionali // se il database è Oracle di tipo thin, allora // String url =” jdbc:oracle:thin:@//localhost:1521/biblio_db“; // // // // se il driver è JDBC-ODBC (tipo1), la url è String url = “jdbc:odbc:biblio_db”; biblio_db è il DSN (Data Source Name) (di solito si crea nei sistemi Windows mediante il Pannello di Controllo) // Se il database è PostGreSQL, allora // String url = “jdbc:postgresql://localhost:5432/biblio_db”; Preparazione dell'istruzione SQL // L'oggetto st rappresenta l'istruzione SQL // Statement è un'interfaccia Statement st = conn.createStatement(); // lancia una SQLException Esecuzione della query (query di lettura) String sql = “SELECT * FROM editori_tbl”; // ResultSet è un'interfaccia ResultSet rs = st.executeQuery(sql); // lancia una SQLException // rs contiene le righe della tabella Il cursore (puntatore al record corrente) adesso è posizionato prima della prima riga Per spostare il cursore in avanti, indietro ecc, possiamo usare i seguenti metodi (booleani): next(), previous(), first(), last(), beforeFirst(), afterLast() ecc Lettura di tutti i record while (rs.next()) { // idEditore è il nome della prima colonna della tabella int idEditore= rs.getInt("idEditore"); // nomeEditore il nome della seconda colonna della tabella String nomeEditore = rs.getString("nomeEditore"); // oppure // int idEditore= rs.getInt(1); // 1 è la posizione della prima colonna // ... // elaborazione dei campi } // fine while Aggiornamento dei record Qualora si voglia effettuare un aggiornamento dei record con le istruzioni SQL INSERT, UPDATE, DELETE (ma anche CREATE), possiamo usare il metodo executeUpdate che restituisce il numero dei record aggiornati in caso di successo. // elimina i record che soddisfano al criterio specificato String url =”DELETE FROM editori_tbl WHERE idEditore = 100”; int result = st.executeUpdate(sql); // lancia una SQLException jdbc-parte1.pdf Pag. 6/7 Cozzetto © Laboratorio di Sistemi Fondamenti di JDBC (parte1) Java if (result>0) { // tutto ok } else { // Impossibile cancellare il(i) record } Query parametriche // troviamo gli editori milanesi // Il ? rappresenta il parametro Sring sql = "SELECT * FROM editori_tbl WHERE cittaEditore = ?"; String citta = "Milano"; // Interfaccia PreparedStatement PreparedStatement ps = conn.prepareStatement(sql); // Associamo al (primo e unico) parametro la stringa citta ps.setString(1, citta); // eseguiamo la query ResultSet rs = ps.executeQuery(); // nessun argomento per il metodo executeQuery, attenzione! // si possono scorrere i record come descritto precedentemente while (rs.next()) { //lettura ed elaborazione dei record // ... } Chiusura degli oggetti // gli oggetti vanno chiusi correttamente nell'ordine inverso a quello di apertura. ps.close(); // lancia una SQLException rs.close(); // idem st.close(); // idem conn.close(); // idem jdbc-parte1.pdf Pag. 7/7 Cozzetto ©