Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
a) definizioni di: vincoli di tupla e vincoli di dominio, chiavi e superchiavi, vincoli di integrità
referenziale.
- I vincoli di integrità sono proprietà che devono essere soddisfatte dalle istanze per garantire la
correttezza delle informazioni. In particolare i vincoli di tupla sono vincoli di integrità valutabili
per ciascuna tupla indipendentemente dalle altre. I vincoli di dominio sono casi particolari di
vincoli di tuple ed esprimono vincoli definiti sui singoli valori delle tuple.
- Una chiave è un insieme di attributi utilizzato per identificare univocamente le tuple di una
relazione.
Nello specifico, dato un insieme K di attributi è superchiave di una relazione r se non contiene
due tuple t1 e t2 con t1[K] = t2[K]; K è chiave di r se è una superchiave minimale di r, ovvero non
esiste un’altra superchiave K’ di r che sia contenuta in K come sottoinsieme proprio.
- I vincoli di integrità referenziale esprimono i legami che intercorrono tra tuple. Un vincolo di
integrità referenziale fra un insieme di attributi X di una relazione R1 e un’altra relazione R2 è
soddisfatto se i valori su X di ciascuna tupla dell’istanza di R1 compaiono come valori della chiave
dell’istanza R2.
1.b) Data una tabella, quali sono le possibili chiavi?
Matricola Cognome Nome Nascita Corso
4328 Rossi Luigi 29/04/59 Ing. Informatica
6328 Rossi Dario 29/04/59 Ing. Informatica
4766 Rossi Luca 01/05/61 Ing. Civile
4856 Neri Luca 01/05/61 Ing. Meccanica
5536 Neri Luca 05/03/58 Ing. Meccanica
- L’insieme {Matricola} è superchiave, ed è anche superchiave minimale in quanto contiene un solo
attributo, quindi {Matricola} è una chiave.
L’insieme {Cognome, Nome, Nascita} è superchiave ma nessuno dei suoi sottoinsiemi è
superchiave, infatti esistono due tuple (prima e seconda) uguali su Cognome e su Nascita, così
come pure le ultime due tuple uguali su Cognome e Nome. Pertanto l’insieme è chiave.
L’insieme {Nome, Corso} non è superchiave, in quanto le ultime due tuple sono identiche, pertanto
l’insieme non può essere chiave.
1.c) A cosa serve l’interfaccia Statement?
- L’interfaccia Statement viene utilizzata per l’esecuzioni di query SQL semplici. In accordo con
l’incapsulamento, con la classe Statement le query SQL vengono specificate all’interno degli oggetti
Statement, differentemente dagli oggetti Prepared Statement in cui le query SQL vengono passate
come parametri di input al costruttore di classe.
Un oggetto di tipo Statement tramite l’oggetto Connection istanza della classe DriverManager
come segue:
// Apertura connessione
connection = DriverManager.getConnection(DbURL, username, password);
// Creazione oggetto Statement
Statement statement = connection.createStatement();
1
2.b) Quali sono i tipi di ristrutturazione?
- Abbiamo quattro tipi di ristrutturazione:
1. Analisi delle ridondanze: per ridondanza, in uno schema concettuale, si intense la
presenza di un dato che può essere derivato da altri dati. Nello specifico del modello E-R i
casi più frequenti di ridondanza sono:
♦ Attributi derivabili, occorrenza per occorrenza da altri attributi della stessa
entità.
♦ Attributi derivabili da attributi di altre entità.
♦ Attributi derivabili da operazioni di conteggio di occorrenze.
♦ Attributi derivabili dalla composizione di associazioni in presenza di cilci.
La presenza delle ridondanze presenta vantaggi e svantaggi. Il vantaggio è una riduzione
degli accessi necessari per controllare il dato derivato, gli svantaggi sono una maggiore
occupazione di memoria e la necessità di effettuare operazioni aggiuntive per mantenere il
dato derivato aggiornato. La decisione di mantenere o meno la ridondanza spetta al
progettista e va presa confrontando il costo di esecuzione delle operazioni che coinvolgono
il dato ridondante e la relativa occupazione di memoria, nei casi di presenza e assenza della
ridondanza.
2. Eliminazione delle generalizzazioni: Ci sono tre modi di ristrutturare una
generalizzazione:
♦ Accorpamento delle classi figlie nella classe padre, per cui le entità figlie vengono
eliminate e le loro proprietà vengono aggiunte all’entità padre; a questa viene
aggiunta un ulteriore attributo che serve a distinguere il “tipo” di una sua occorrenza
(Esempio: PERSONA viene accorpato con le classi figlie UOMO e DONNA, a persona
viene aggiunto l’attributo Sesso per sapere a quale occorrenze della classe figlia ci si
sta riferendo).
Questa alternativa è conveniente quando le operazioni non fanno molta distinzione
tra le occorrente e tra gli attributi della classe padre e delle classi figlie; infatti, anche
se abbiamo uno spreco di memoria per via della presenza di possibili valori nulli, si
riduce notevolmente il numero degli accessi.
♦ Accorpamento del padre della generalizzazione nelle figlie, per cui l’entità padre
viene eliminata e, per la proprietà dell’ereditarietà, i suoi attributi, il suo
identificatore e le relazioni a cui tale entità partecipava, vengono aggiunti alle entità
figlie.
Questa soluzione è possibile solo quando la generalizzazione è totale, altrimenti le
occorrenze della classe padre che non sono occorrenze di nessuna delle classi figlie
non sarebbero rappresentate. In questo caso si ha un risparmio di memoria, dal
momento che non avremo mai valori nulli.
♦ Sostituzione della generalizzazione con associazioni, per cui la generalizzazione si
trasforma in tante associazioni uno a uno che legano rispettivamente l’entità padre
con ogni entità figlia. Non ci sono trasferimenti di attributi o associazioni e le entità
figlie sono identificate esternamente dall’entità padre.
Questa alternativa è conveniente quando la generalizzazione non è totale e ci sono
operazioni che si riferiscono solo a occorrenze delle entità figlie o dell’entità padre, e
dunque fanno distinzione tra l’entità padre e le entità figlie.
2
In questo caso abbiamo un risparmio di memoria rispetto alla prima alternativa, ma
si ha un incremento degli accessi per mantenere la consistenza delle occorrenze
rispetto ai vincoli introdotti.
3. Partizionamento/Accorpamento di concetti: si suddivide in:
♦ Partizionamento di entità: quando una entità viene suddivisa in due entità legate da
una relazione. Un partizionamento di questo tipo prende il nome di decomposizione
verticale di un’entità quando si suddivide il concetto operando sui suoi attributi,
mentre prende il nome di decomposizione orizzontale quando la suddivisione avviene
sulle occorrenze dell’entità.
♦ Eliminazione degli attributi multi valore: questa ristrutturazione si rende
necessaria perché, come per le generalizzazioni, il modello relazionale non permette di
rappresentare in maniera diretta questo tipo di attributo.
Gli attributi multi valore diventano entità legate, con un’opportuna relazione, all’entità
di cui era attributo.
4. Scelta degli identificatori principali: questa scelta è importante per la traduzione verso il
modello relazionale perche in questo modello le chiavi vengono usate per stabilire i legami
tra dati in relazioni diverse.
I criteri per effettuare una opportuna scelta degli identificatori sono:
♦ Gli attributi con valori nulli non possono costituire identificatori principali;
♦ Un identificatore composto da uno o da pochi attributi è da preferire a
identificatori costituiti da molti attributi;
♦ Un identificatore interno con pochi attributi è da preferire a un identificatore
esterno;
♦ Un identificatore che viene utilizzato da molte operazioni per accedere alle
occorrenze di una entità è da preferire rispetto agli altri.
2.c) Quali sono i criteri su cui ci si basa per fare accorpamenti/partizionamenti di entità?
- Il principio generale che viene seguito è il seguente: gli accessi si riducono separando attributi di
uno stesso concetto che vengono acceduti da operazioni diverse e raggruppando attributi di
concetti diversi che vengono acceduti dalle medesime operazioni.
Il partizionamento di entità avviene, per lo più, quando ci sono relazioni che frequentemente
coinvolgono soltanto alcuni dei suoi attributi. Gli accorpamenti si effettuano in genere su
associazioni di tipo uno a uno, raramente su associazioni uno a molti e mai su associazioni molti a
molti, questo perché negli ultimi due casi generano ridondanze. Questi avvengono quando ci sono
operazioni che richiedono contemporaneamente le informazioni di entrambe le entità coinvolte
dalla relazione (es. le entità PERSONA e APPARTAMENTO legate dalla relazione INTESTAZIONE,
quando ci si riverisce a PERSONA quasi sempre si cercano le informazioni relative
all’appartamento).
3
3.b) Esercizio di traduzione da schema E-R a schema logico
4
3.c) Cosa fa la classe DriverManager? Qual'è il suo metodo più importante e come si fa a caricare un
driver?
- La classe DriverManager contiene al suo interno tutti i driver di database registrati e permette di
associarli ai database stessi. Istanziando un oggetto Driver esso viene automaticamente registrato
nella classe DriverManager.
Il metodo più importante di questa classe è il metodo getConnection() che di fatto apre il canale di
connessione col database.
5
4.b) Scelto un DBMS e realizzata un'applicazione in java, se decidessi di cambiare driver l'applicazione, a
livello di codice, andrebbe modificata?
- L’unica linea di codice da modificare è quella dove avviene la stringa di codice in cui il driver viene
caricato, quindi va cambiato il percorso del driver nell’istruzione Class.forName()
4.c) Se si decidesse invece di cambiare DBMS, le istruzioni SQL andrebbero modificate?
- Adottando l’architettura Bridge JDBC/ODBC nel momento in cui si decide di cambiare DBMS le
istruzioni SQL non vanno modificate in alcun modo. Questo perché l’architettura scelta lascia che
sia ODBC a gestire le query, e quindi di tradurle in base al DBMS utilizzato.
4.d) Data una query SQL in uno specifico DBMS, la stessa va bene per tutte e quattro le strutture JDBC?
- Questo è vero soltanto nelle strutture Middleware-Server e Driver JDBC.
Il motivo sta nel fatto che i tipi 3 e 4 prevedono che il driver sia interamente scritto in Java, mentre i
primi due tipi no; infatti il tipo JDBC/native bridge si interfaccia con codice scritto in altri linguaggi
(che non sono il Java) che esegue le chiamate finali per il database ed esso è compilato per l'uso su
un particolare sistema operativo. Il tipo JDBC/ODBC Bridge invece ,si serve di ODBC, che a sua volta
utilizza le librerie del sistema operativo. Quindi i primi due tipi sono estremamente dipendenti dalla
piattaforma, gli altri due invece sono molto piu portabili (prorio perche scritti in Java).
4.e) Quali sono i costrutti del diagramma E-R?
- I principali costrutti del modello E-R sono: entità, relazioni, attributi, cardinalità, identificatori delle
entità e generalizzazioni
4.f) Cardinalità di attributi, relazioni ed entità
- Le entità sono classi di oggetti con proprietà comune ed esistenza autonoma ai fini
dell’applicazione di interesse, esempi di entità all’interno di una realtà aziendale possono essere
IMPIEGATO, CITTA’, DIPARTIMENTO. Un occorrenza di una entità altro non è che un oggetto della
classe rappresentata dall’entità; Roma, Milano e Napoli sono esempi di occorrenze dell’entità
CITTA’. È importate sottolineare il fatto che una occorrenza di un oggetto non rappresenta un
valore assunto dall’oggetto, bensì l’oggetto stesso. Conseguenza di quanto detto è il fatto che una
occorrenza di una entità esiste a prescindere dalle proprietà ad essa associate.
Le relazioni rappresentano i legami logici che intercorrono tra due o più entità. RESIDENZA può
essere un esempio di relazione che potrebbe intercorrere tra le entità IMPIEGATO e CITTA’. Una
occorrenza di una relazione è una ennupla costituita dalle occorrenze delle entità coinvolte; la
coppia delle occorrenze Rossi di IMPIEGATO e Firenze di CITTA’ rappresentano una occorrenza della
relazione RESIDENZA. Va precisato che più relazioni possono coinvolgere le stesse entità, ad
esempio RESIDENZA e SEDE DI LAVORO sono due relazioni che possono coinvolgere le entità
IMPIEGATO e CITTA’. È importate sottolineare il fatto che l’insieme delle occorrenze di una
relazione del modello E-R altro non è che una relazione matematica tra le occorrenze delle entità
coinvolte, quindi sarà un sottoinsieme del loro prodotto cartesiano. Questo significa che
nell’insieme non potranno mai esserci delle ennuple ripetute. Infine le relazioni possono essere
ricorsive, ovvero sono relazioni tra una entità e se stessa.
Gli attributi descrivono le proprietà elementari di entità o relazioni che sono di interesse ai fini
dell’applicazione; nome, cognome e età sono possibili attributi dell’entità IMPIEGATO. Un attributo
associa ad ogni occorrenza di entità o relazione un valore appartenente ad un insieme, detto
dominio, contiene i valori assumibili per l’attributo. Il dominio non viene riportato sullo schema ma
viene tenuto presente nella documentazione associata.
Le cardinalità di attributi descrivono il numero minimo e massimo di valori dell’attributo associati
ad ogni occorrenza di entità o relazione. Nella maggior parte dei casi gli attributi hanno cardinalità
(1,1), quindi viene omessa, e l’attributo viene detto obbligatorio. Se l’attributo può avere valore
6
nullo allora la cardinalità minima deve essere 0 e l’attributo viene detto opzionale, mentre se può
assumere più valori la cardinalità massima deve essere pari ad N e viene detto multivalore.
6.a) Come si progetta un'applicazione JDBC? A cosa serve in particolare la parte di Elaborazione
dell'applicazione?
- La progettazione di un’applicazione JDBC può essere riassunta in 6 passi:
1. Caricamento del Driver specifico del DB che si intende utilizzare: il driver è fornito
da chi produce il DBMS e, quindi, per effettuare la registrazione basta caricare la classe
fornita dal produttore del particolare DBMS che s’intende usare, utilizzando l’istruzione
Class.forName(“class-driver”), dove class driver è il nome della classe che implementa il
driver.
7
2. Apertura di una connessione al DB, associata all'utilizzo di un oggetto di tipo
java.sql.Connection: in JDBC ogni database viene univocamente identificato dal suo JDBS
URL così strutturato: jdbc:<driver>:<origine_dati> dove il primo termine indica il
protocollo, il secondo termine il driver che bisogna utilizzare, il terzo la risorsa a cui ci si
vuole connettere. Per aprire la connessione bisogna istanziare un oggetto della classe
Connection e ciò può essere fatto usando il metodo getConnection(String url) throws
SQLException della classe DriverManager che instaura una connesisone col database
indicato dal parametro url.
3. Creazione di un oggetto di tipo java.sql.Statement: la creazione dell’oggetto Statement
serve per poter eseguire le operazioni una volta stabilita la connessione col database. Il
metodo che permette di farlo è public Statement create Statement( ) della classe
Connection.
4. Esecuzione di uno o più comandi sul DB attraverso i metodi messi a disposizione
dall'oggetto Statement precedentemente creato: i metodi sono:
Ø Int executeUpdate(String sql) utilizzata per le istruzioni diverse dalla SELECT,
restituisce il numeri di righe che sono state inserite o aggiornate o cancellat,
oppure restituisce 0 in caso di istruzioni DDL;
Ø ResultSet executeQuery(String sql) usata per l’istruzione di SELECT, restituisce
un oggetto ResultSet che è un cursore, simile ad un iteratore, che ci permette di
scorrere fra le righe di una tabella prodotto di una SELECT.
5. Elaborazione del risultato: vengono elaborati in modo opportuno, a seconda delle
esigenze, i risultati delle operazioni sul database
6. Chiusura del DB:: è importante chiudere la connessione al database altrimenti si rischia
di saturare il numero massimo di connessioni al database, rendendo poi impossibile
l’accesso.
6.b) Come si effettua una connessione alla base di dati usando JDBC?
- Per aprire la connessione bisogna istanziare un oggetto della classe Connection e ciò può essere
fatto usando il metodo getConnection(String url) throws SQLException della classe DriverManager
che instaura una connessione col database indicato dal parametro url. Tutto questo avviene a mo
8
3. Sostituzione della generalizzazione con associazioni, per cui la generalizzazione si
trasforma in tante associazioni uno a uno che legano rispettivamente l’entità padre con
ogni entità figlia. Non ci sono trasferimenti di attributi o associazioni e le entità figlie sono
identificate esternamente dall’entità padre.
Questa alternativa è conveniente quando la generalizzazione non è totale e ci sono
operazioni che si riferiscono solo a occorrenze delle entità figlie o dell’entità padre, e
dunque fanno distinzione tra l’entità padre e le entità figlie.
In questo caso abbiamo un risparmio di memoria rispetto alla prima alternativa, ma si ha
un incremento degli accessi per mantenere la consistenza delle occorrenze rispetto ai
vincoli introdotti.
7.b) Cos'è la classe PreparedStatement? Quali sono i principali metodi e a cosa servono?
- La classe PreparedStatement è una classe messa a disposizione da Java per inviare Query SQL.
I metodi più importanti di PreparedStatement invece sono: setString(pos, value) e setInt(pos,
value), dove pos è la posizione del parametro della query SQL parametrica a cui assegnare la
stringa/intero value.
Poi ci sono executeUpdate(sql) ed executeQuey(sql): il primo esegue una query di
aggiornamento/inserimento/cancellazione, restituendo il numero di righe aggiornate; il secondo
esegue una query di selezione, restituendo un oggetto di tipo ResultSet, cioe una tabella con le
righe e le colonne selezionate nella query.
7.c) Qual'è il vantaggio nell'uso di un PreparedStatement rispetto ad uno Statement?
- Uno dei suoi primi vantaggi sta nel fatto che garantisce la completa indipendenza dalla piattaforma,
anche e soprattutto per quanto riguarda il linguaggio SQL.
Spesso, durante la fase di sviluppo di un progetto, si è soliti suddividere i compiti tra più squadre in
modo da ottimizzare i tempi di produzione. Accade, in questi casi, che ogni team possa decidere di
utilizzare un proprio DBMS per eseguire determinate parti di codice, senza la necessità di
preoccuparsi di quale poi sia il DB da utilizzare in fase di deployment o di uniformarsi al DB
utilizzato dagli altri gruppi di sviluppo.
Nonostante JDBC garantisca l'indipendenza dalla piattaforma, il problema che può nascere è che il
linguaggio SQL utilizzato negli statement potrebbe non esserlo.
Un esempio classico è rappresentato dall'utilizzo degli apici e doppi apici all'interno di una query. Si
consideri la seguente stringa:
Se la si esegue su MySQL essa non darà alcun problema e aggiornerà la tabella Employee come
richiesto.
Se il DB utilizzato fosse Sybase la stringa di aggiornamento precedente produrrà un errore (quindi
un'eccezione sul codice Java).
JDBC viene incontro al problema di compatibilità appena evidenziato attraverso una interfaccia
denominata java.sql.PraparedStatement.
Oltre a questo vantaggio, attraverso tale interfaccia, è possibile sfruttare al meglio il meccanismo di
caching messo a disposizione dalla maggior parte dei data base.
Molti DBMS mantengono in cache le istruzioni SQL precedentemente utilizzate e le mettono a
disposizione qualora venga inviata al DB stesso un'istruzione analoga. Quindi utilizzando un
comando già compilato e ottimizzato si ha un miglioramento generale delle performance.
Tale ragionamento è valido, però soltanto se le istruzioni pervenute sono esattamente identiche in
forma e contenuto. Ovvero, se pervenissero in tempi diversi, le due istruzioni:
9
insert into Employee values ('Mario', 'Rossi', 'Analyst')
insert into Employee values ('Marco', 'Bianchi', 'Analyst')
il meccanismo di caching non potrebbe essere utilizzato, in quanto pur effettuando la medesima
operazione (inserimento nella tabella Employee), la seconda istruzione contiene valori differenti e
rappresenta un'istruzione SQL differente.
Il problema si risolverebbe facilmente passando al database un comando SQL che contenga una
serie di variabili, in modo che il DB possa riutilizzare lo stesso comando ogni volta, senza
preoccuparsi dei valori cui le variabili stesse fanno riferimento. I Prepared Statement mettono in
pratica proprio tale strategia.
Inoltre mentre con gli Statement l’istruzione viene inviata al database di volta in volta, col Prepared
Statement l’istruzione viene compilata una sola volta, in modo che le chiamate successive siano più
efficienti.
Quindi, concludendo, l’interfaccia Prepared Statement risolve i problemi di efficacia ed efficienza
che si ponevano nel caso dell’interfaccia Statement.
11
Le soluzioni più utilizzate del CLI sono l’ODBC (Open DataBase Connectivity), proposta dalla
Microsoft, e il JDBS (Java DataBase Connectivity) della Sun Microsystem.
12