Sei sulla pagina 1di 46

Programmare e Progettare

con Java.
Lezione 9 - Ripasso SQL, Gestione Dati Permanenti con DAO
RIPASSO DATABASE
DBMS
Il DBMS (DataBase Management System) è un sistema SW progettato per
consentire creazione, manipolazione e interrogazione efficiente dei database. È il
nostro modo di interfacciarci con la base di dati, parte fondamentale di
un’applicazione che vuole mantenere dati in modo permanente.

Per questa lezione, il DMBS di riferimento sarà MySQL, un DBMS gratuito.

https://dev.mysql.com/downloads/installer/

Scegliere l’opzione “Developer Default” e completare l’installazione.

L’interfaccia di gestione è aperta da “MySQL Workbench”.


CONFIGURAZIONE MYSQL
1. “Type and Networking” -> Lasciare default, Next.
2. “Authentication Method” -> Usare quella raccomandata, Next.
3. “Accounts and Roles” -> Scegliere una password facile da ricordare. Fare
“Add User” e stabilire nome utente e password, impostando come ruolo “DB
Admin”. Confermare e fare Next.
4. “Windows Service” -> Lasciare valori di default o dare un nome al servizio e
decheckare l’autoboot.
5. “Apply Configuration” -> Execute.
MODELLO ER - ENTITÀ
Il modello ER permette di rappresentare graficamente le entità di cui vogliamo
immagazzinare dati e le relazioni tra tali entità. Costituisce un buon punto di partenza per
la realizzazione delle basi di dati e costituisce la loro progettazione concettuale.

Protagoniste sono le entità: classi di oggetti che possono esistere fisicamente o


concettualmente. Tutte le entità hanno attributi, ovvero le loro proprietà particolari.

Un database in genere contiene gruppi di entità simili che condividono gli stessi attributi
ma che hanno i propri valori per essi. Tali gruppi sono detti tipi di entità.

Le entità vengono rappresentate da rettangoli, mentre gli attributi possono essere


rappresentati come pallini dotati di nome o cerchi che lo contengono.
MODELLO ER - CHIAVE
Una chiave è un vincolo sugli attributi che fanno in modo che la loro
combinazione abbia valori distinti di tupla in tupla.

Una chiave minimale è detta superchiave e di queste ne viene scelta una che è la
chiave primaria. In realtà, nei diagrammi ER, tale concetto non esiste, ma
possiamo metterci avanti!

Una chiave si indica annerendo il pallino degli attributi chiave o barrandoli con una
linea nera con pallino ad un’estremità se la chiave è composta da più attributi;
altrimenti si indica sottolineando il nome.
MODELLO ER - ASSOCIAZIONI
Ogni volta che un attributo di un tipo di entità si riferisce a un altro tipo di entità, allora sussiste una
qualche associazione. Un tipo di associazione tra n tipi di entità E1, E2, …, En definisce un insieme di
legami tra le entità di questi tipi. Ognuno di questi tipi di entità si dice partecipare all’associazione.

Il grado di un’associazione è il numero di entità che vi partecipano.

Una associazione può avere attributi.

Le associazioni hanno due vincoli:

➔ cardinalità: Si applica alle associazioni binarie (a 2 entità) e specifica il numero massimo di istanze
di associazione a cui può partecipare un’entità. Si hanno 1:1, 1:N, N:1 e N:M.
➔ partecipazione: Specifica se l’esistenza di un’entità dipende dal suo essere correlata ad un’altra
attraverso il tipo di associazione; in pratica, ci dice il numero minimo di istanze a cui ogni entità può
partecipare. Può essere totale (minimo 1) o parziale (minimo 0).
ESEMPIO SQL 1
ESEMPIO SQL 2
PROGETTAZIONE LOGICA
Si divide in due parti:

1. Ristrutturazione: Si sistema il diagramma ER eliminando elementi non


competenti alla base di dati finale. In genere parliamo di dati derivati,
gerarchie di generalizzazione, attributi multivalore e composti.
2. Traduzione: Traduciamo ogni singolo elemento grafico in un descrittore di
una tabella SQL.

La prima parte in genere è molto rapida e un sistemista esperto in genere già


rappresenta il modello ER privo degli elementi sopracitati. Guardiamo quindi alla
traduzione...
RELAZIONE
Ogni parte dello schema ER deve essere tradotta in relazioni: E={K, W} dove K è
l’identificatore e W sono gli attributi descrittivi. Per esteso:

E(a1,a2,...,at, at+1, at+2,..., at+k)

K è detta chiave primaria.


1) TRADUZIONE ENTITÀ
Partendo da uno schema ristrutturato…

1) Per ogni tipo di entità E si costruisce una relazione R che contiene tutti gli
attributi di E.
2) Come PK di R si sceglie un attributo chiave di E che può essere un singolo
attributo o anche più attributi.
2) TRADUZIONE ASSOCIAZIONI 1:1
1) Per ogni tipo di associazione R si individuano le relazioni S e T corrispondenti
ai tipi di entità che partecipano ad R.
2) Si segue uno dei seguenti approcci:
a) Basato su chiavi esterne: Si sceglie una delle due relazione (S) e vi si inserisce come FK la
PK di T, rendendola attributo di S e denotandola tramite una sottolineatura tratteggiata. Come
S è meglio scegliere una relazione con partecipazione totale a R. In S si inseriscono tutti gli
attributi semplici di R.
b) Basato sulla relazione fusione: Si possono fondere i due tipi di entità e l’associazione in
un’unica relazione solo se entrambe le entità hanno partecipazione totale ad essa.
c) Basato sulla reale associazione: SI crea una terza relazione R inserendovi le PK di S e T
come FK verso S e T. La PK di R sarà una delle due FK.
3) TRADUZIONE ASSOCIAZIONI 1:N
1) Per ogni tipo di associazione R si individua l’associazione S che partecipa
come 1.
2) Si inserisce in S la PK di T come FK verso T e tutti gli attributi semplici del tipo
di associazione.

Si può utilizzare anche qui la relazione associazione: la PK sarà la PK si S.


4) TRADUZIONE ASSOCIAZIONI M:N
1) Per ogni tipo di associazione R si costruisce la relazione S che rappresenta
R.
2) Come FK di S si inseriscono le PK delle relazioni partecipanti e la loro
combinazione sarà la PK di S.
3) Si inseriscono tutti gli attributi semplici del tipo di associazione.
SQL
SQL (Standard Query Language) è un linguaggio di interrogazione che permette
di gestire e interrogare i database.

Esso ha una sintassi semplice che permette interrogazioni complesse a partire da


schemi di tabelle.

Tutte le operazioni effettuate da interfacce DBMS come MySQL Workbench si


traducono in operazioni SQL.

Ripassiamo le 4 principali operazioni.


INSERT
INSERT è l’istruzione che consente di inserire tuple (righe) alla nostra relazione
(tabella).

INSERT INTO nomeTabella (listaAttributi) VALUES (listaValori)

La listaValori deve elencare i valori nello stesso ordine degli attributi, se non li si
specifica nella listaAttributi.
UPDATE
UPDATE è l’istruzione che consente di aggiornare le tuple, modificando i valori di
una relazione.

UPDATE nomeTabella SET modifica [WHERE condizione]

La clausola WHERE specifica quali tuple debbano essere modificate. Se la si


tralascia vengono modificate tutte!

La modifica è spesso un assegnamento.

La condizione è una condizione booleana!


DELETE
DELETE è l’istruzione che permette di cancellare tuple da una relazione.

DELETE FROM nomeTabella [WHERE condizione]

La clausola WHERE specifica quali tuple debbano essere cancellate. Se la si


tralascia vengono cancellate tutte!

La condizione è una condizione booleana!


SELECT
SELECT è l’istruzione più importante di SQL in quanto permette di effettuare le
query.

SELECT listaAttributi FROM listaTabelle [WHERE condizioni]

Esso seleziona una listaAttributi dalla listaTabelle secondo una condizione e la


reperisce.

Le condizioni usano l’algebra booleana!


JOIN
Il JOIN è un’operazione che permette di recuperare dati da combinazioni di
tabelle. Tale operatore combina un certo numero di tabelle.

SELECT listaAttributi_r, listaAttributi_s

FROM tabella_r JOIN tabella_s ON chiavePrimaria = chiaveEsterna

[WHERE condizioni]
ESERCIZI
● A partire dall’esempio ER 2, creare un database su MySQL passando
attraverso la progettazione logica.
● Popolare le tabelle realizzate con almeno 5 righe ciascuna.
● Fare l’UPDATE di tutte le righe di Corso, cambiando il nome in “JavaGaldus”.
● Cancellare tutte le righe da Master; quindi ripopolarle.
● Recuperare il codice si Docente e Corso di tutte le associazioni esistenti tra
essi.
GESTIONE DATI PERMANENTI
JDBC
JDBC (Java DataBase Connectivity) è una API Java che permette di connettersi
e di eseguire query con il database. Questo ci consente di interrogare e gestire un
database a partire da Java, così da salvare dati in modo permanente così da
poterli recuperare a nuovi avvii delle nostre applicazioni.

Grazie a JDBC possiamo effettuare le seguenti operazioni:

1. Connetterci al DB
2. Eseguire interrogazioni e aggiornamenti del DB
3. Elaborare i risultati ottenuti dal DB
STRUTTURA DI JDBC
JDBC è quindi un insieme di classi e interfacce orientate alla comunicazione con
database di varia natura. Tali tipi sono inclusi nel pacchetto java.sql che quindi
abbiamo il bisogno di importare in qualsiasi nostra applicazione Java che voglia
sfruttare tali servizi.
Tra questi tipi, quelli più importanti sono:
★ Classe DriverManager
★ Interfaccia Driver
★ Interfaccia Connection
★ Interfaccia PreparedStatement
★ Interfaccia ResultSet
DRIVER
Il problema fondamentale di aprire una comunicazione con un DB è che stiamo
cercando di mettere in comunicazione due applicazioni diverse che non sono state
progettate per avere punti di interfacciamento.
Serve quindi un driver, un programma che faccia come ponte tra la nostra
applicazione Java e il database.
Ogni tipo di database ha però regole diverse e quindi il driver cambia a seconda
del DBMS in uso.
Noi usiamo SQL, quindi useremo il driver apposito scaricabile al seguente link:
https://drive.google.com/file/d/1ylaQ_fUcuLlJoxdqrhHkgmDCCN5uwG9Q/view?us
p=sharing
INSTALLARE IL DRIVER
Il driver è spesso posto in un JAR messo a disposizione dal produttore del DBMS.
Esso deve essere aggiunto al Classpath della nostra applicazione, in quanto
rappresenta una libreria.

Per farlo, basta seguire i passi visti per l’import di librerie tramite JAR!

1. Mettere il JAR in una cartella lib interna al progetto.


2. Cliccare con il destro sul JAR e, alla voce Build Path, selezionare Add to Build
Path.
3. Il dirver ora è installato! È ora possibile utilizzare i tipi visti nelle slides
precedenti!
SETUP DELLA CONNESSIONE
La classe Connection ci permette di realizzare la comunicazione con il database.
Colui che ne opera l’apertura, però, è il DriverManager: esso mette a
disposizione uno speciale metodo getConnection() in grado di instaurarla!

❖ Connection getConnection(String url) throws SQLException


➢ Permette di aprire una connessione verso il DB identificato da url e restituisce un oggetto che
la identifica.

La stringa url deve seguire un determinato formato, inoltre si noti che tale metodo
solleva un nuovo tipo di eccezione! Si raccomanda di effettuare ogni operazione
riguardante i database in un blocco try-catch che gestisca almeno SQLException!
FORMATO DI URL
Cosa ha bisogno di conoscere il DriverManager?
➔ Il tipo del database, per capire che driver usare.
➔ L’indirizzo del database, per capire dove trovarlo.
➔ Le credenziali d’accesso, per capire chi vuole accedervi.
➔ Il nome dello schema a cui riferirsi.
Queste informazioni sono interne alla Stringa url.
Essa segue il seguente formato:
jdbc:mysql://[host:port], [host:port], ...
/[database][?proprietà1][=valore1][&proprietà2][=valore2]...
PARTI DI URL
❏ mysql Nel nostro caso, ma potrebbe essere un qualsiasi altro DBMS!
❏ host Nome dell’host che è quasi sempre localhost.
❏ port Numero della porta. Non lo si mette se di default (3306).
❏ database Nome dello schema.
❏ proprietà Specifiche di connessione, come user e password!

La nostra stringa tipo sarà quindi la seguente:

ES: String url =


“jdbc:mysql://localhost/nomeSchema?user=nomeUser&password=userPassword”
ESEGUIRE STATEMENT SQL
Mettiamo immediatamente le mani avanti: noi non vogliamo che sia possibile fare
SQL injection! Non useremo mai quindi oggetti di tipo Statement, ma
PreparedStatement, che permette di eseguire le operazioni in modo atomico!
Questa interfaccia permette di creare template di istruzioni SQL dotate di
parametri (bind variable) che vengono sostituiti con valori effettivi al momento
dell’esecuzione. Ad ES:
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users
WHERE userid=? AND password=?");
I ‘?’ sono le sopracitate bind variable, mentre connection è un riferimento ad un
oggetto di tipo Connection.
ASSEGNARE LE BIND VARIABLES
Per dare un valore alle bind variables dobbiamo utilizzare il metodo setTipo()
dell’interfaccia PreparedStatement:

❖ void setTipo(int parameter, Tipo value)


➢ Imposta il parametro numero parameter come value del tipo indicato.

Ad ES:

stmt.setString(1, “admin”);

stmt.setString(2, “psw”);
ESEGUIRE GLI STATEMENT
Eseguire una query è diverso dall’eseguire un altro tipo di operazione poiché una query dà come ritorno
un certo numero di righe frutto dell’interrogazione. Per questo motivo, il metodo per eseguire le query è
diverso da quello usato per le altre operazioni (a cui ci riferiamo come updates).

Per eseguire una query, utilizziamo il seguente metodo di PreparedStatement:

❖ ResultSet executeQuery()
➢ Esegue lo statement a cui si fa riferimento, facendo tornare un set di risultati.

Per un update:

❖ int executeUpdate()
➢ Esegue lo statement a cui si fa riferimento, facendo tornare il numero di righe da esso aggiornate.

Ad ES:

ResultSet rs = stmt.executeQuery(); oppure int tot = stmt.executeUpdate();


GESTIRE IL RESULTSET
ResultSet è una collezione di risultati di una query. Possiamo pensare ad un Set
in cui ogni elemento è una riga del DB. Per navigare al suo interno, viene
generato un cursore che inizia prima del primo elemento.
Il metodo next() di ResultSet avanza di 1 riga, così come previous() retrocede di
una.
Per recuperare un valore dalla riga, abbiamo due strade:
❖ Tipo getTipo(int col)
➢ Restituisce il valore della colonna col (a partire da 1) del tipo che ci aspettiamo.
❖ Tipo getTipo(String nome)
➢ Restituisce il valore della colonna nominata come nome.
MAPPING TRA I TIPI DI SQL E JAVA
CHIUDERE LE RISORSE
Quando abbiamo finito, chiudiamo tutte le risorse che abbiamo aperto tramite gli
appropriati close().

Dobbiamo chiudere:

❏ L’oggetto Connection
❏ L’oggetto PreparedStatement
❏ L’oggetto ResultSet
ESEMPIO DI QUERY
ESERCIZI
● Attraverso l’uso di JDBC, popolare il database creato nell’esercizio
precedente con un certo numero di righe.
● Per ogni tabella, effettuare la stampa in un file di tutto il contenuto della
tabella. Deve esserci un file per tabella!
DAO
UN PROBLEMA… PERSISTENTE
La persistenza dei dati di una applicazione Java attraverso JDBC è sicuramente
utile, ma richiede che vengano generate manualmente delle query SQL che sono
stringhe che vengono passate come argomenti a delle funzioni.

Quello che si va a fare è una sorta di traduzioni da classi Java a istruzioni SQL e
viceversa!

Questa traduzione è operata per ogni classe del modello che necessita
persistenza e per ogni operazione sul database!

Abbiamo un problema di paradigm mismatch (Object/Relational mismatch).


PARADIGM MISMATCH
Le associazioni nell’ottica OO sono direzionali (realizzate con riferimenti ad
oggetti) mentre i DBMS relazionali usano le chiavi esterne che non sono
direzionali. Inoltre, mentre in OO possiamo avere associazioni N:M, nei RDBMS
(Relational DBMS) abbiamo solo associazioni 1:N e 1:1 (le N:M in questo caso
sono state trasformate in due relazioni 1:N e N:1).
I RDBMS non supportano nemmeno il concetto di ereditarietà e polimorfismo
anche se supportano le supertable e subtable, l’ereditarietà applicata alle classi è
una ereditarietà di tipo e una tabella non è un tipo.
Per via di problemi come questi, il database viene progettato dopo aver stabilito il
diagramma delle classi senza un mapping preciso classe-tabella… il che genera il
paradigm mismatch.
ALTRI PROBLEMI
Oltre quanto visto nella slide precedente, ci troviamo di fronte ad un problema di
codice molto confuso e poco organizzato poiché abbiamo:

❏ Informazione di basso livello riguardo connessione al DB, creazione di query,


etc… mischiato insieme al resto dell’applicazione.
❏ Poca portabilità e manutenibilità a causa del variare dei settaggi dei DB (o dei
DBMS) da sistema a sistema.
❏ Codice complesso da leggere e quindi da capire.
IL DESIGN PATTERN DAO
Il Design Pattern DAO (Database Access Object) è una soluzione al problema di
paradigm mismatch e a tutti i problemi che riguardano l’implementare JDBC
all’interno della propria applicazione.

Esso si prefigge come obiettivi:

➔ Separare in classi ad hoc tutto il codice che gestisce gli accessi al DB.
➔ Ottenere classi dell’applicazione indipendenti da quelle di interazione con il
DB, magari riutilizzando delle parti.

Qui un buon riferimento a comprendere la teoria del DAO con un buon esempio.
SOLUZIONE DI DAO
Separare le classi in:

★ Classi “Client”: Devono accedere ai database, ignorando i dettagli legati


all’interazione con il DBMS: connessione, query, schema, etc…
★ Classi “DAO”: Contengono e incapsulano tutti gli accessi al database,
costituendo così gli unici oggetti che interagiscono direttamente con il DB.
Ignorano il modo di usare i dati delle classi Client.
DAO - DIAGRAMMA DELLE CLASSI
ESERCIZI
● A partire dal database generato per l’esercizio 2, progettare per mezzo del
diagramma delle classi un’applicazione che possa utilizzarlo.
● Modificare il progetto così da implementare DAO per tutte le sue classi che
trovano un parallelo nel DB.
● Provare ad implementare il codice.

Potrebbero piacerti anche