2. Cosa è JDBC JDBC significa Java Database Connectivity Standard definito da Sun MicroSystems per connettere programmi Java ai database relazionali E' costituito da un insieme di classi e interfacce scritte in Pure Java Si basa sul concetto di driver di database Il driver è una implementazione JDBC specifica per database Permette ai diversi fornitori di database di estendere lo standard con i loro specifici driver JDBC (Oracle, MySQL, MS SQL Server)
3. Cosa fa JDBC Stabilisce una connessione con il database Invia comandi SQL Processa il risultato
4. Come si usa JDBC Import dei package java.sql.* Registrazione del driver (Oracle, MySQL) Apertura connessione Creazione oggetto Statement Esecuzione query e recupero dati dal ResultSet Utilizzo ResultSet Chiusura risorse ResultSet e Statement Chiusura connessione
5. I passi da eseguire DriverManager Driver Connection Statement ResultSet
6. JDBC Registrazione Driver Per utilizzare un driver di database un'applicazione lo deve rendere disponibile applicazione (si chiama registrazione del driver) Questo si fa ad esempio come prima istruzione del metodo main public static void main(String[] args) throws Exception { Class. forName ( JDBC_DRIVER ).newInstance(); ... ... } Nell'esempio JDBC_DRIVER e' un stringa contenente il nome del driver
7. JDBC Apertura connessione /1 La classe java.sql.DriverManager permette di creare connessioni I metodi per creare una connessione sono getConnection(String url, String user, String password) throws SQLException Tenta di stabilire una connessione tramite una URL utilizzando user e password getConnection(String url) throws SQLException Tenta di stabilire una connessione tramite una URL L'overload del metodo con un solo paramentro permette di passare user e password direttamente sulla URL Tutti i metodi di JDBC lanciano l'eccezione java.sql.SQLException
8. JDBC Apertura connessione /2 Una connessione rappresenta una sessione con uno specifico db Le sessioni sono risorse preziose in un db e bisogna gestirle con cura Si possono avere può connessioni contemporanee con il db E' possibile ottenere informazioni sulla struttura del db (metadata) E' possibile gestire le transazioni In JDBC spesso si usano i connection pool per ottimizzare gli accessi alle connessioni
9. La URL JDBC La URL contiene varie informazioni macchina (e porta) dove gira il database nome dell'istanza del database Cambia per ogni database (Oracle, MySQL) jdbc:oracle:thin:[user/password]@[host][:port]:SID jdbc:mysql://[host]:[po]/[dbname] Viene usato lo pseudo protocollo jdbc:
10. Eseguire uno statement Il codice mostrato ottiene una connessione ad database (linea 2) esegue uno statement di select (linea 5) public void eseguiSelect() throws SQLException { Connection conn = DriverManager . getConnection ( JDBC_URL , JDBC_USER , JDBC_PASSWORD ); Statement st = conn.createStatement(); st.executeQuery( "select * from Animale" ); st.close(); conn.close(); }
11. Interfaccia java.sql.Statement Viene usato il metodo Connection.createStatement per ottenere una interfaccia JDBC per eseguire istruzioni SQL statiche Una istruzione si dice statica quando non ci sono variabili JDBC che modificano la query st.executeQuery( "select * from Animale where nome = 'Fido'" ); La condizione di where è statica se il nome cambia dovrei costruire la query in modo diverso, ad esempio concatenando la stringa st.executeQuery( "select * from Animale where nome = '" + nome + "'" );
12. Alcuni metodi dell'interfaccia java.sql.Statement execute(Stringsql) Esegue una espressione SQL che può ritornare risultati multipli executeQuery(Stringsql) Esegue una espressione SQL che ritorna un solo oggetto ResultSet executeUpdate(Stringsql) Esegue una espressione SQL che può essere: INSERT, UPDATE, or DELETE Perché tutti questi metodi così simili? Per sfruttare le ottimizzazioni del database il programmatore sa cosa vuole e richiama il metodo più appropriato
13. Interfaccia java.sql.ResultSet Un ResultSet fornisce l'accesso ai dati di una tabella generati eseguendo uno Statement Si può aprire un solo ResultSet alla volta Il ResultSet mantiene un cursore alla riga corrente ottenuta dal database
14. Alcuni metodi di java.sql.ResultSet java.sql.Date getDate(intcolumnIndex) double getDouble(intcolumnIndex) int getInt(intcolumnIndex) String getString(intcolumnIndex) Il parametro in ingresso, columnIndex, indica la posizione del campo nella select E' possibile passare il nome del campo anziché la posizione java.sql.Date getDate(StringcolumnName)
15. Chiusura risorse Si e' detto che le connessioni sono risorse preziose per cui vanno rilasciate appena possibile Lo stesso vale per Statement e ResultSet La chiusura avviene utilizzando il metodo close() Connection.close() Statement.close(); ResultSet.close();
16. Esempio di select completo private void stampaNomi(Connection conn) throws SQLException { String query = "select nome from Animale order by nome"; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery( query ); while (rs.next()) { String nome = rs.getString( "nome" ); System. out .println( "Nome = " + nome); } rs.close(); st.close(); }
17. Esercizio /1 SELECT JDBC Sul database sono presenti due tabelle gia' popolate Scrivere un programma che stampi i nomi ed il tipo di animale uno per riga L'output atteso e' mostrato in Figura Nome = fido descrizione = canide Nome = polly descrizione = uccello Nome = silvestro descrizione = felino Nome = titty descrizione = uccello
18. Non solo select /1 Statement.executeUpdate Quando si vuole eseguire una INSERT su database si deve usare executeUpdate private void inserisciCavalli(Connection conn) throws SQLException { Statement st = conn.createStatement(); st.executeUpdate( "insert into animale (nome, fk_tipo) values ('furia', 'cavallo');" ); st.executeUpdate( "insert into animale (nome, fk_tipo) values ('fulmine', 'cavallo');" ); st.close(); }
19. Non solo select /2 executeUpdate executeUpdate viene usato anche per UPDATE e DELETE E' possibile conoscere quanti record sono stati interessati dall'operazione di UPDATE/DELETE utilizzando il valore ritornato private void eliminaCavalli(Connection conn) throws SQLException { Statement st = conn.createStatement(); int count; count = st.executeUpdate( "delete from animale where fk_tipo = 'cavallo'" ); System. out .println(String. format ( "Eliminati %d cavalli" , count)); st.close(); }
20. Esercizio /2 UPDATE JDBC Scrivere un programma che permetta di rinominare un animale Il metodo renameAnimale deve prendere 4 argomenti connessione nuovo nome vecchio nome tipo animale Stampare un messaggio che indichi se l'operazione ha avuto successo Quando l'operazione ha avuto successo?
21. Indipendenza dal database /1 Le query che abbiamo visto contengono le stringhe che intendiamo usare nelle clausole WHERE nei valori delle INSERT Ma cosa succede se le stringhe hanno caratteri particolari? Ad esempio apici o doppie virgolette
22. Indipendenza dal database /2 La soluzione e' quella di fare l'escape ma questo e' un compito oneroso per il programmatore ogni database ha regole diverse Oracle usa gli apici per definire una stringa MySql usa anche le doppie virgolette "select * from Animale where nome = '" + nome + "'" "delete from animale where fk_tipo = 'cavallo'" "insert into animale (nome, fk_tipo) values ('furia', 'cavallo');"
23. Indipendenza dal database /3 Il lavoro di escape deve essere fatto dal driver JDBC Ogni driver conosce le proprie regole (Oracle sa come fare l'escape delle proprie stringhe) le differenze non riguardano solo le stringhe, possono coinvolgere anche numeri interi numeri in virgola mobile ma soprattutto le date (ogni database ha un suo formato per definire una data ad esempio in una clausola WHERE) Il codice di accesso al DB viene scritto una sola volta
24. Indipendenza dal database /3 Connection.PreparedStatement Per risolvere il problema e' sufficiente utilizzare la classe PreparedStatement al posto di Statement Non si usa il metodo Connection.createStatement ma Connection.prepareStatement I valori da associare vengono sostituiti con il carattere punto interrogativo Per impostare i parametri si usano i metodi setString / setDate / setXXX
25. Indipendenza dal database /4 Connection.PreparedStatement Differenze di codifica tra createStatement... String sql = "select a.nome from ANIMALE a, TIPO_ANIMALE t" + " where a.fk_tipo=t.tipo" + " and t.tipo=?" ; // con ? si definisce un parametro PreparedStatement st = conn.prepareStatement(sql); // riceve la query st.setString(1, tipoAnimale); ResultSet rs = st.executeQuery(); String sql = "select a.nome from ANIMALE a, TIPO_ANIMALE t" + " where a.fk_tipo=t.tipo" + " and t.tipo='" + tipoAnimale + "'" ; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql); // executeQuery riceve la query ... e prepareStatement
26. Esercizio /3 Utilizzare PreparedStatement Modificare il codice di renameAnimale in modo che funzioni con PreparedStatement
27. Oggetti VO e DAO La scrittura di codice java per l'accesso al database e' stata razionalizzata dividendo logicamente il codice Vengono create due gerarchie di classi contenenti Oggetti che rappresentano la struttura della tabella Oggetti che effettuano SELECT/INSERT/UPDATE/DELETE Questa classificazione non e' obbligatoria ma agevola la suddivisione in gerarchie ben definite
28. Oggetti VO /1 Value Object Un value object e' una rappresentazione Java di una tabella Per la tabella ANIMALE esistera' la classe Animale Per la tabella TIPO_ANIMALE esistera' la classe TipoAnimale Le classi altro non sono che dei bean con getter e setter (non hanno logica)
29. Oggetti VO /2 Value Object public class Animale { private String nome ; private String tipo ; public String getNome() { return nome ; } public void setNome(String nome) { this . nome = nome; } public String getTipo() { return tipo ; } public void setTipo(String tipo) { this . tipo = tipo; } }
30. Oggetti DAO /1 Data Access Object Queste classi interagiscono con il database e utilizzano i VO La connessione viene passata al costruttore oppure ai singoli metodi Per la tabella ANIMALE esistera' una classe AnimaleDAO L'output di un DAO (se presente) dovrebbe essere sempre del tipo della tabella che rappresenta Eventuali JOIN tra piu' tabelle diventano dettagli implementativi
31. Oggetti DAO /2 Data Access Object public class AnimaleDAO { public List ricercaByTipo(Connection conn, String tipoAnimale) throws SQLException { ... // il codice che crea il PreparedStatement e' stato omesso List list = new ArrayList(); while (rs.next()) { Animale a = new Animale(); a.setNome(rs.getString(1)); a.setTipo(tipoAnimale); list.add(a); } return list; } }
32. Esercizio /4 VO e DAO Creare gli oggetti VO e DAO per Animale Creare i metodi utilizzando il pattern VO/DAO per Cercare per nome e per tipo Inserire un nuovo animale Rinominare un Animale Cancellare un Animale