Articoli Manifesto Tools Links Canali Libri Contatti ?
Linguaggi / Java

Java e database: introduzione a JDBC

Abstract
Java possiede ormai da tempo JDBC, uno strato di astrazione specifico per i database relazionali, in questo articolo verrà fatta una panoramica su cos'è JDBC e come si usi.
Data di stesura: 12/11/2003
Data di pubblicazione: 01/12/2003
Ultima modifica: 04/04/2006
di Federico Paparoni Discuti sul forum   Stampa

Java è un linguaggio che fa del multipiattaforma la sua arma principale. Infatti ultimamente c'è stato il suo massiccio utilizzo anche nelle tecnologie embedded come cellulari (J2ME) e sim (JavaCard). Per rendere onore a questa filosofia del multipiattaforma, dell'astrazione dal singolo sistema operativo, i progettisti della Sun non potevano che progettare una libreria di accesso ai database coerente. JDBC è un API Java che fornisce uno strato di accesso verso i database completo e soprattutto ad oggetti, c'è indipendenza dal tipo di database e l'accesso viene generalizzato a livello di applicazione.

Progettando un'applicazione Java che utilizzi JDBC ci troviamo davanti a due successivi «strati»: DriverLayer e ApplicationLayer.

Il DriverLayer è lo strato di JDBC che si occupa dell'interfacciamento con il database mentre l'ApplicationLayer riguarda le funzionalità che JDBC offre per manipolare dati tramite costrutti Java.

[Figura 1]

Figura 1

Il DriverLayer è essenzialmente composto dall'interfaccia Driver e dalla classe DriverManager. Il Driver è il vero e proprio driver che ci permette il collegamento al database e che richiamiamo nel nostro programma, mentre il DriverManager gestisce l'instaurazione della connessione con il database e la restituzione della connessione al nostro programma, anche se in molti casi è più conveniente crearsi da soli un proprio DriverManager per particolari esigenze, come ad esempio pooling di connessioni.

L'ApplicationLayer , che riguarda appunto più il lato applicativo, è principalmente composto dalle interfacce Connection, Statement, ResultSet, PreparedStatement edSQLException. Connection è quella che modella la connessione al database e serve per creare gli Statement o i PreparedStatement che sono i costrutti che ci permettono di eseguire interrogazioni, modifiche e inserimenti verso il database. I PreparedStatement sono praticamente degli Statement quasi completi ai quali dobbiamo passare dei parametri, anche a run-time, e quindi migliorano l'efficienza specialmente in programmi ripetitivi. L'oggetto che modella i dati che il database ci restituisce in prima istanza dopo una query è il ResultSet, mentre l'SQLException è una semplice classe che estende Exception e che tramite opportuni metodi ci permette di venire a conoscenza degli errori generati dalla nostra applicazione riguardanti JDBC.

Prima di immergerci in qualche riga di codice dobbiamo parlare dei driver che permettono il collegamento al database. In un primo momento infatti un ingenuo programmatore non riesce bene a capire le sottili differenze dei driver che si trova davanti quando vuole collegare la sua applicazione ad un database. Invece le differenze ci sono e sono importanti. Bisogna prima di tutto dire che esistono 4 diversi tipi di driver JDBC:

  1. JDBC-ODBC
  2. JAVA e API del DB
  3. Driver di rete in JAVA
  4. Driver nativo in JAVA

Il primo è un driver che usa un driver ODBC e converte le chiamate JAVA per questo driver. Non è indipendente dalla piattaforma e solitamente ha delle prestazioni scadenti. La seconda soluzione sfrutta una libreria del DB e quindi traduce sempre le chiamate JAVA, però ha una prestazione migliore del primo pur non essendo indipendente dalla piattaforma. Il driver di rete è un ottima soluzione visto che sfrutta un server intermedio tra applicazione e DB, avendo quindi un driver molto leggero. Questo chiaramente però conviene solo nel caso che la rete non sia congestionata o che si tratti di una LAN. Infine c'è il driver nativo in JAVA, che comunica direttamente col database, indipendente dalla piattaforma e con buone prestazioni. Chiaramente i migliori sono quelli del terzo e quarto tipo (anche se non sempre sono disponibili) , dipendenti anche dalla natura dell'applicazione che deve essere sviluppata.

Una volta che abbiamo l'SDK Java, il database e il driver per la connessione ad esso possiamo ad iniziare a collegarci ad esso. Per il caricamento del driver e la connessione abbiamo bisogno della classe DriverManager. Per caricare il driver usiamo Class.forName al quale passiamo il nome del driver. Ad esempio il caricamento del driver per Oracle 9i Lite è il seguente:

  1. Class.forName(«oracle.lite.poljdbc.POLJDBCDriver»); 

Questo metodo sfrutta il blocco di inizializzazione statica del Driver. Successivamente il DriverManager ci restituisce una connessione al database, incapsulandola nell'oggetto Connection , tramite il suo metodo getConnection al quale devo passare come argomento un URI (Uniform Resource Identificator), un login e una password. L'URI è della forma jdbc:<protocollodb>:<parametri>. Ecco quindi la connessione al database:

  1. String URI    = "jdbc:polite:EsempioDb"; 
  2. // oppure jdbc:polite://127.0.0.1/EsempioDb 
  3.  
  4. String LOGIN  = "system"; 
  5. String PASSWD = "manager"; 
  6.  
  7. Connection conn = DriverManager.getConnection(URI, LOGIN, PASSWD); 

In questo modo è avvenuta la nostra connessione al database. Se qualcosa non è andato a buon fine in questa connessione iniziale Java lancerà una SQLException che dovrà quindi essere opportunamente catturata dalla nostra applicazione. SQLException è utilissimo al programmatore visto che dispone di due metodi che permettono un veloce e semplice determinazione del problema.

Il metodo getErrorCode() di questa classe restituisce il codice d'errore deciso da chi ha fatto il database, quindi facilmente consultabile, mentre il metodo getSQLState() restituisce al programmatore una stringa contenente lo «stato» del DB in maniera conforme alle specifiche XOPEN o SQL99 (dipende dal DB), dando comunque al programmatore un semplice diretto messaggio che può portare subito all'individuazione del problema.

A questo punto Java ci offre tre semplici oggetti che semplificano la nostra vita per inviare e ricevere informazioni al database: Statement, PreparedStatement e ResultSet.

Lo Statement viene creato attraverso il metodo createStatement() di Connection. Ci sono due metodi importanti della classe Statement e sono executeQuery(String) ed executeUpdate(String). Il primo serve per interrogazioni al database (SELECT) mentre il secondo per inserimenti, aggiornamenti e cancellazioni (INSERT, UPDATE, DELETE).

Il metodo executeQuery(String) restituisce un ResultSet , un oggetto-tabella che rappresenta i dati selezionati dalla nostra interrogazione. Poi noi dobbiamo visitare questo ResultSet per vedere quali sono i dati e utilizzarli nel modo voluto. Questo oggetto viene letto come con un puntatore che grazie al metodo next() passa alla successiva riga della tabella che abbiamo avuto come risposta. Ecco un esempio di utilizzo:

  1. try{ 
  2. 	String URI="jdbc:polite:EsempioDb"; 
  3. 	String LOGIN="system"; 
  4. 	String PASSWD="manager"; 
  5. 	Connection conn=DriverManager.getConnection(URI, LOGIN, PASSWD); 
  6. 	//Creiamo lo Statement necessario per eseguire l'interrogazione che vogliamo 
  7. 	//tramite il metofo executeQuery che ci restituisce una lista di studenti che 
  8. 	//abbiamo nel nostro database 
  9. 	Statement stat = conn.createStatement(); 
  10. 	ResultSet rs = stat.executeQuery("SELECT NOME,COGNOME,DATA,ETA FROM STUDENTI"); 
  11.  
  12. 	//Utilizziamo il metodo next() del ResultSet per poter scandire man mano 
  13. 	//tutte le righe della tabella che c'è stata restituita.  Per ogni riga 
  14. 	//utilizziamo un metodo getXXX dove XXX è il tipo di dato contenuto nel 
  15. 	//database. In questo caso passiamo a questi metodi dei numeri per riferirci 
  16. 	//al numero di colonna della tabella che viene restituita ma potevamo passare 
  17. 	//direttamente anche il nome della stessa. 
  18. 	while (rs.next()) { 
  19. 		System.out.println("Nome "+rs.getString(1)); 
  20. 		System.out.println("Cognome "+rs.getString(2)); 
  21. 		System.out.println("Data Di Nascita "+rs.getDate(3)); 
  22. 		System.out.println("Età "+rs.getInt(4)); 
  23. 		System.out.println("- - - - - - - - -"); 
  24. catch(SQLException e) { 
  25. 	//Abbiamo catturato un eccezione generata dalle istruzioni precedenti e 
  26. 	//scriviamo a schermo il contenuto dell'eccezione, che in caso di errore 
  27. 	//logico relativo al database ci restituirà l'errore che ci restituisce il 
  28. 	//database. 
  29. 	System.out.println(e.getMessage()); 
  30. finally{ 
  31. 	//Cerchiamo, qualsiasi sia stato l'errore, di chiudere lo statement e la 
  32. 	//connessione 
  33. 	try{ 
  34. 	stat.close(); 
  35. 	conn.close(); 
  36. 	catch(SQLException ex) 
  37. 	{System.out.println(ex.getMessage());} 

Infine per ottimizzare la nostra applicazione utilizziamo i PreparedStatement. Facciamo un esempio, invece di scrivere 50 volte la query per l'update di 50 studenti nel database la scrivo una volta e poi le passo di volta in volta che voglio inserire dei nuovi studenti dei parametri:

  1. // I punti interrogativi sono i valori che saranno conosciuti a runtime 
  2. // dall'applicazione 
  3. PreparedStatement ps=conn.prepareStatement( 
  4. 	"UPDATE STUDENTI SET MEDIA=? WHERE NOME=?"); 
  5.  
  6. // Immaginiamo di avere un vettore V con i valori da aggiornare che  
  7. // scorriamo fino alla fine 
  8. int i=0; 
  9. while (!V.isEmpty()) { 
  10. 	// setto a 22 il valore MEDIA 
  11. 	ps.setInt(1,(int)V.get(i)); 
  12. 	// setto uguale a Luca il valore di NOME 
  13. 	ps.setString(2,(String)V.get(i+1)); 
  14. 	// Niente parametri per il metodo in questo caso 
  15. 	ps.executeUpdate(); 
  16. 	i=i+2; 

Oltre a questo Java e database come Oracle permettono l'inserimento di classi e metodi Java all'interno del db, la scelta del livello di isolamento per il database, trigger, pool di connessioni, metodi di incapsulamento ... ma questa è un'altra storia.

Informazioni sull'autore

Federico Paparoni, studente di Ingegneria Informatica, appassionato da anni di programmazione. Nutre profondo amore per tutta la documentazione che riesce a trovare online riguardante l'interesse del momento. Predilige la programmazione sfrenata (notte tempo!) in qualsivoglia linguaggio (se non lo conosce si impara tanto alla fine sono tutti uguali). Specializzato nel linguaggio Java, ultimamente collabora con la W-LAB srl per lo sviluppo di applicazioni su dispositivi mobili riguardanti VoiceXML e Bluetooth. Mantiene un server irc presso l'università insieme ad un gruppo di geek.

È possibile consultare l'elenco degli articoli scritti da Federico Paparoni.

Altri articoli sul tema Linguaggi / Java.

Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.