Java 04

2,094 views
2,029 views

Published on

Introduzione all'uso di JDBC

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,094
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
66
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Java 04

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

×