POLITECNICO DI MILANO ANALISI COMPARATA TRA DATABASE

POLITECNICO DI MILANO
Polo Regionale di Como
Facoltà di Ingegneria dell’Informazione
Corso di Studi in Ingegneria Informatica
ANALISI COMPARATA TRA
DATABASE AD OGGETTI E
DATABASE OBJECT RELATIONAL
Tesi di Laurea di:
Relatore:
RIVA MATTEO
RONCHETTI LUCA
Prof. Fraternali Piero
Correlatore:
Ing. Brambilla Marco
Anno Accademico 2003/2004
2
Capitolo 1 Introduzione ..................................................................................4
1.1 Finalità del lavoro ....................................................................................................................4
1.2 Analisi del problema ................................................................................................................4
1.3 Organizzazione dell’elaborato ................................................................................................5
Capitolo 2 Tecnologie utilizzate ...........................................................6
2.1 Introduzione alle basi di dati .................................................................................................6
2.1.1 Basi di dati relazionali ................................................................................................................7
2.1.2 Basi di dati Object Relational .......................................................................................................8
2.1.3 Basi di dati ad oggetti .................................................................................................................8
2.2 Introduzione a SQL ...............................................................................................................10
2.2.1 Storia di sql e panoramica del linguaggio .....................................................................................10
2.2.2 Definizione delle strutture dati e inserimenti .................................................................................11
2.2.3 Selezione dei dati ....................................................................................................................12
2.2.4 Modifiche ai dati memorizzati ....................................................................................................14
2.2.5 Funzionalità di SQL-3 estese agli oggetti .....................................................................................15
2.3 Introduzione allo standard ODMG ......................................................................................22
2.3.1 Storia dello standard.................................................................................................................23
2.3.2 Architettura dello standard ........................................................................................................23
2.3.3 Modello dei dati ......................................................................................................................23
Capitolo 3 Confronto tra i vari DBMS .....................................28
3.1 Differenze tra i vari DBMS ...................................................................................................28
3.2 Panoramica dei prodotti in commercio................................................................................31
3.3 Criteri di valutazione per la scelta dei prodotti da analizzare...........................................32
Capitolo 4 Oracle 9i (ORDBMS) .....................................................33
4.1 Breve storia del prodotto.......................................................................................................33
4.2 Architettura ............................................................................................................................34
4.3 Tipi di dati ..............................................................................................................................35
4.4 Funzionalità SQL99 implementate.......................................................................................36
4.5 Creazione dello schema .........................................................................................................37
4.6 Tools dedicati..........................................................................................................................38
Capitolo 5 Versant (OODBMS) .........................................................42
5.1 Breve storia del prodotto.......................................................................................................42
5.2 Caratteristiche........................................................................................................................42
5.3 Installazione............................................................................................................................44
5.4 Tipi di dati ..............................................................................................................................46
5.5 Creazione dello schema .........................................................................................................50
3
5.6 Tools dedicati..........................................................................................................................51
Capitolo 6 Applicazione d’esempio ...............................................53
6.1 Descrizione..............................................................................................................................53
6.2 Specifiche ................................................................................................................................53
6.3 Linguaggio utilizzato..............................................................................................................55
6.4 Implementazione con ORDBMS ..........................................................................................55
6.5 Implementazione con OODBMS ..........................................................................................57
6.6 Manuale utente.......................................................................................................................58
Capitolo 7 Conclusioni ..................................................................................61
Bibliografia .......................................................................................................................64
4
Capitolo 1 Introduzione
1.1 Finalità del lavoro
Il lavoro svolto nell’elaborato è consistito nell’analisi comparata di due tecnologie per la
memorizzazione persistente di dati attraverso DBMS, una già in forte sviluppo (Object-Relational),
mentre l’altra non ancora così ampiamente diffusa (Object-Oriented). Si sono perciò analizzati due
dei tanti prodotti in commercio per evidenziare le caratteristiche peculiari di ognuno. Infine si è
sviluppata una semplice applicazione con lo scopo di mostrare le differenze tra i due
prodotti(ORDBMS, OODBMS) a livello di programmazione.
1.2 Analisi del problema
La maggior parte della programmazione è orientata agli oggetti: questo ha reso l’utilizzo di un
DBMS relazionale puro complicato da gestire in quanto risulta difficile mappare logicamente gli
oggetti in tabelle. Le basi di dati relazionali, infatti, sono un insieme di tabelle dove le colonne
definiscono la struttura della tabella stessa, mentre le righe contengono i dati. Questo ha
comportato, in fase di sviluppo, a pensare ed a descrivere il mondo in termini di record, progettando
il modello dei dati con questi concetti semplicistici. Un'altra caratteristica dei sistemi relazionali è il
supporto di un linguaggio dichiarativo di interrogazione normalizzato (SQL). Questo linguaggio è
stato concepito per il modello relazionale pertanto permette di inserire, aggiornare, eliminare
righe(Data Manipulation Language) e aggiungere o cancellare colonne, tabelle o indici(Data
Definition Language). SQL risulta, dal punto di vista dei programmatori, non essere bene integrato
nei linguaggi di programmazione procedurali in quanto ogni produttore di questa tecnologia
definisce delle estensioni proprietarie di SQL (non normalizzate) per rendere il sistema usabile; ad
esempio query ricorsive, outer join, etc. Infine, riguardo agli RDBMS, essi hanno tipicamente
un’architettura centralizzata; tutte le operazioni del database sono eseguite a lato server, con il
rischio di creare dei “colli di bottiglia” e un calo evidente delle performance al crescere delle
connessioni simultanee verso il db.
Con l’utilizzo della tecnologia OR, invece, e le aggiunte alle funzionalità SQL estese agli oggetti, il
mapping diventa maggiormente trasparente permettendo di sviluppare in modo più efficace. Per
fare questo, i sistemi OR introducono due nuove caratteristiche:
• Nuovi tipi di dato
• Attributi complessi
La prima caratteristica permette di trattare con tipi di dato prima non presenti come dati
multimediali o di creare strutture di dati complesse definiti dall’utente(Abstract Data Type). Questi
tipi di dato sono più o meno integrati con la struttura relazionale e il linguaggio di interrogazione;
inoltre non essendo la tecnologia di tipo Object-Oriented, viene a mancare il supporto
all’ereditarietà. La seconda caratteristica permette per esempio di creare una nuova tabella con
un’altra tabella come attributo. Questo per simulare la relativa associazione nel modello a oggetti.
Per quanto riguarda la tecnologia OO (OODBMS), l’approccio cambia radicalmente in quanto la
suddivisione logica dei dati in tabelle è assente. Il modello a oggetti è più ricco rispetto a quello
relazionale; in molte implementazioni, un oggetto è un’istanza di una classe. Una classe è usata sia
come modello per la creazione dell’oggetto(nel db), sia come modello per istanziare tipi di quella
classe(nel linguaggio di programmazione).
Le classi definiscono il comportamento e lo stato dei loro oggetti. Lo stato è definito dai valori di un
insieme di attributi, mentre il comportamento da un insieme di metodi.
L’idea base di un OODBMS è di memorizzare direttamente oggetti complessi nel database senza
limitazioni nei concetti Object-Oriented supportati.Un sistema OODBMS non è una
5
rappresentazione costruita attorno ad un RDBMS, ma provvede completamente alla gestione del
database attraverso la memorizzazione fisica degli oggetti stessi.
1.3 Organizzazione dell’elaborato
L’elaborato presenta 7 capitoli. Dopo una breve introduzione del lavoro svolto, il capitolo 2
descrive le tecnologie utilizzate focalizzandosi sui diversi tipi di basi di dati, sul linguaggio di
interrogazione SQL con le relative estensioni e sullo standard ODMG.
Dopo questa panoramica, il capitolo 3 confronta le principali categorie di DBMS attraverso dei
parametri comuni.
I capitoli 4 e 5 entrano nel dettaglio per quello che riguarda i prodotti analizzati, rispettivamente
Oracle 9i e Versant.
Il capitolo 6 riguarda l’applicazione sviluppata per evidenziare le differenze nell’approccio tra una
tecnologie ed un’altra; oltre a definire i prerequisiti dell’applicazione d’esempio (demo) il capitolo
in questione presenta anche un manuale utente semplificato.
Infine con il capitolo 7 si evidenziano le conclusioni cui si è arrivati con la fine del lavoro.
6
Capitolo 2 Tecnologie utilizzate
2.1 Introduzione alle basi di dati
Una base di dati (BdD) è una collezione di dati correlati. Per dati s’intendono fatti noti che possono
essere memorizzati e che hanno un significato implicito.
Le caratteristiche fondamentali di una base di dati sono:
• Numerosità di dati. Cioè una quantità di dati che non possono stare sulla memoria
principale. Una problematica è quindi il trasferimento dei dati dalla memoria secondaria a
quella principale. Un fattore di complessità è il numero di trasferimenti dei dati dalla
memoria secondaria alla principale.
• Persistenza dei dati: non ho una situazione di questo tipo quando i dati creati dal programma
esistono solo durante l’esecuzione del programma (vengono cancellati con la chiusura del
programma). I dati invece devono esistere prima e dopo la durata dell’esecuzione del
programma.
• Globalità dei dati: i dati di interesse di un programma sono locali; i dati invece devono
essere di interesse per una pluralità di programmi.
Una base di dati può essere di qualsiasi dimensione e di diversa complessità.
Un sistema di gestione di basi di dati (DBMS: DataBase Management System) è un insieme di
applicazioni le quali permettono agli utenti di creare e mantenere una base di dati. Il DBMS è perciò
un sistema software con scopi generali (general – purpose software system) che facilita il processo
di definire, costruire e manipolare una base di dati per varie applicazioni. Definire una base di dati
implica specificare i tipi di dati, le loro strutture e i vincoli per i dati che devono essere
memorizzati. Costruire la base di dati significa immagazzinare i dati stessi entro un certo mezzo di
memorizzazione che è controllato dal DBMS. Manipolare una base di dati include funzioni come la
sua interrogazione per recuperare dati specifici, il suo aggiornamento per rispecchiare cambiamenti
nel mini-mondo e la generazione di prospetti (reports) a partire dai dati.
Ci sono in ogni modo più dibattiti che consensi nella definizione di che cosa sia un DBMS.
In generale comunque si riscontrano 3 categorie base per la definizione e differenziazione di un
DBMS:
• Modello dei dati
• Linguaggio di interrogazione
• Modello computazionale
Per modello dei dati s’intende una definizione o descrizione completa della sua struttura e dei
vincoli della base di dati. Questa definizione è memorizzata nel catalogo di sistema, che contiene
informazioni come la struttura di ciascun file, il tipo e il formato di memorizzazione di ciascun dato
e vari vincoli sui dati. Le informazioni memorizzate nel catalogo sono dette metadati e descrivono
la struttura della base di dati principale. Il catalogo è usato dal software del DBMS e anche dagli
utenti della Base di dati che hanno bisogno di informazioni sulla struttura della stessa.
L’analisi della realtà implica la scelta di un metodo di studio e di progettazione delle strutture dati e
delle relazioni che esistono tra di loro. Questo è in pratica ciò che viene chiamato con il nome di
schema.
È importante distinguere tra la descrizione della base di dati e la base di dati stessa. La descrizione è
detta schema della base di dati (data-base schema); esso è specificato durante la progettazione della
base di dati e non ci si aspetta che cambi frequentemente. Una rappresentazione grafica di uno
schema è detta diagramma di schema. Ciascun oggetto dello schema si chiama costrutto dello
schema.
7
Un diagramma di schema rappresenta solo certi aspetti di uno schema, come i nomi dei vari tipi di
record e dei dati, e alcuni tipi di vincoli; altri aspetti non vengono specificati. Molti tipi di vincoli
non sono rappresentati nei diagrammi di schema; I dati nella base di dati in un particolare istante di
tempo costituiscono lo stato della BdD o l’istantanea della BdD. Si parla anche di insieme di
occorrenze o istante nella BdD. Lo schema logico che definisce la struttura e la tipologia dei dati ivi
contenuti si chiama albero di definizione.
Nel modello relazionale è più che mai importante imparare a ragionare in termini di entità e
relazioni. Un’entità è in pratica un oggetto definito di per sé con alcune caratteristiche dette attributi
o proprietà. Un generico campo che ospita più dati può essere in relazione con un altro. Nel modello
relazionale la definizione delle relazioni è essenziale per legare i dati tra loro e gestirli al meglio con
facilità.
Esistono diversi tipi di relazione: uno a uno (indicata anche con 1 : 1); uno a molti (1 : n); molti a
uno (n : 1) o molti a molti (n : m). Per la rappresentazione delle entità e delle relazioni è parecchio
utilizzato il cosiddetto modello entity - relationship (ER).
Il modello relazionale permette di gestire le informazioni attraverso tabelle permanenti (i dati che
vengono effettivamente memorizzati sul database) e tabelle risultato (le interrogazioni o query per
estrarre le informazioni cercate). Una riga di una tabella viene chiamata tupla, così come una
colonna viene chiamata dominio. Il numero di righe viene chiamato cardinalità della relazione e può
variare nel tempo. Il numero delle colonne non dovrebbe variare nel tempo (a meno che non si
voglia intervenire sulla tabella a livello strutturale) e viene espresso con il termine grado.
Il linguaggio di interrogazione è il modo con cui si estraggono i dati dalla base di dati.
I linguaggi sono ormai standardizzati e dipendono dal tipo di database.
Il modello computazionale consiste nel modo di gestire le associazioni dei dati all’interno della base
di dati.
2.1.1 Basi di dati relazionali
Modello dei dati - Un RDBMS (Relational DataBase Manegement System) consiste in una o più
tabelle composte da righe e colonne. Le righe corrispondono a record (Tuple); le colonne
corrispondono ad attributi (Campi nel record). Ogni colonna ha un tipo di dato. I tipi di dati che
possono essere utilizzati sono pochi. Ad esempio character, string, time, date, number and currency.
Ogni attributo (campo) del record può immagazzinare solo un singolo valore. I campi di lunghezza
variabile non sono supportati. Le relazioni non sono esplicite, ma derivate da valori in specifici
campi. Le relazioni molti-a-molti richiedono una tabella intermedia che contiene unicamente le
relazioni.
Linguaggio di interrogazione - Una vista è un sottoinsieme di un database che è il risultato di
un’interrogazione (query). In un RDBMS una vista è una tabella. Gli RDBMS usano SQL come
linguaggio per la definizione, la gestione e l’accesso ai dati. I dati localizzati in base al valore di un
certo campo in un record. I tipi di query supportate variano da semplici interrogazioni di singole
tabelle a complicate interrogazioni di più tabelle.
Modello computazionale – Tutto il processo è basato sui valori dei campi nei record. I record non
hanno identificatori unici che rimangono immutati durante la vita della tupla. Non ci sono modi di
referenziamento da un record ad un altro. L’esame del risultato di una query è fatto sotto il controllo
di un cursore che permette all’utente di vedere un record alla volta.
Questo impone di pensare e descrivere il mondo in termini di array, progettando il modello dei dati
con questi concetti. Un'altra caratteristica degli RDBMS è la loro architettura centralizzata. Tutte le
operazioni del database sono effettuate a lato server, creando evidentemente un collo di bottiglia
con calo delle performance nel momento in cui ci sono più connessioni aperte simultaneamente.
8
2.1.2 Basi di dati Object Relational
Modello dei dati – Le basi di dati Object Relational (ORDBMS) utilizzano un modello dei dati che
aggiunge al modello relazionale le funzionalità estese agli oggetti. Tutte le informazioni sono
ancora persistenti in tabelle, ma i dati possono avere una struttura più complessa. Questi tipi di dati
sono detti astratti (ADT). Un ADT (Abstract Data Type) è un dato costruito dalla combinazione di
tipi di dati elementari. Il supporto degli ADT è attraente in quanto le operazioni e le funzioni
associate ai dati possono essere utilizzate per indicizzare, immagazzinare e recuperare record basati
sul contenuto dei nuovi dati.
Linguaggio di interrogazione – Un ORDBMS supporta una estensione di SQL . Il punto
dell’estensione è il supporto del modello ad oggetti. Le estensioni includono query che coinvolgono
oggetti innestati, attributi settati, inclusioni di metodi e funzioni e query che hanno a che fare con
dati astratti. Un ORDBMS è ancora relazionale perché i dati sono immagazzinati in tabelle e SQL è
il linguaggio per la definizione, la manipolazione e l’interrogazione. Il risultato di una query sono
sempre tabelle o tuple.
Modello computazionale – Il linguaggio SQL, con le estensioni per accedere agli ADT, è ancora la
prima interfaccia del database. Il supporto diretto dei linguaggi ad oggetti e i loro oggetti continua a
mancare forzando i programmatori a continuare a tradurre tra oggetti e tabelle.
2.1.3 Basi di dati ad oggetti
Modello dei dati – L’idea di base di un ODBMS è di memorizzare direttamente object model
complessi in un database, senza limitazioni per concetti object-oriented supportati (Fig. 2-1). Un
ODBMS non è una rappresentazione che lavora attorno un RDBMS, ma mette a disposizione un
completo database management con uno spazio fisico di memorizzazione degli oggetti.
Fig. 2-1. Object mapping
9
Quando gli oggetti sono memorizzati in memoria, implicitamente durante la navigazione
trasparente, o esplicitamente durante le query, si trovano in un’area speciale della heap della Java
Virtual Machine, sotto il controllo di un object manager (OM). L’OM trasformerà i puntatori in
OID e viceversa, processerà trasparentemente tutti gli oggetti dal server ogni volta che è necessario,
e marcherà gli oggetti modificati che saranno poi aggiornanti dal server alla successiva commit.
Inoltre il modello dei dati permette l’uso di un identificatore (OID) per referenziare ogni istanza
persistente di una classe (Fig. 2-2).
A seconda dell’implementazione, questo identificatore può essere fisico o logico, e distribuito o no.
Fig. 2-2. OID
Il modello dei dati supporta l’incapsulamento di dati e metodi, l’ereditarietà multipla e gli ADT
(Abstract Data Types).
I database ad oggetti combinano gli elementi dell’orientamento agli oggetti e la programmazione di
linguaggi orientati agli oggetti con le capacità del database. Il risultato è un alto livello di
congruenza tra il modello dei dati per l’applicazione ed il modello dei dati del database,
riscontrabile nel minor volume di codice scritto, nonché in una maggiore manutenibilità e riusabilità
del codice.
Il modello a oggetti dello standard ODMG3 specifica due tipi di oggetti: oggetti e letterali. Esso
definisce a sua volta 2 tipi di caratteristiche degli oggetti: operazioni e proprietà. Le proprietà
possono essere sia attributi che relazioni. I database a oggetti possono supportare efficientemente
ogni tipo di struttura, inclusi alberi e oggetti composti.
Uno dei punti di forza del modello ad oggetti è l’abilità nel definire referenziazioni, o relazioni tra
oggetti. Usando linguaggi ad oggetti, queste referenziazioni sono implementate con i puntatori.
Quando si memorizza un oggetto che ne referenzia altri, l’ODBMS cambia lo stato degli oggetti
puntati da volatili a persistenti.
Per fare questo, gli OID sono usati come referenziatori unici e persistenti. Una volta nel database un
oggetto si riferisce ad un altro attraverso il suo OID. Una volta ricaricati nella memoria, gli OID
sono mappati trasparentemente in puntatori. Navigare con gli OID non è solo più elegante, ma è
anche un modo più efficiente per rintracciare gli oggetti.
Linguaggio di interrogazione – Un linguaggio orientato agli oggetti (C++, Smalltalk, Java) è il
linguaggio sia per l’applicazione che per il database. Esso provvede ad una relazione diretta tra
l’oggetto dell’applicazione e l’oggetto persistente nella base di dati. La definizione dei dati, la
manipolazione e l’interrogazione riflettono questa relazione.
Lo standard ODMG-93 definisce anche un linguaggio dichiarativo (OQL) per interrogare una base
di dati a oggetti. OQL non è completamente compatibile con SQL. Il risultato di una query OQL
può essere un atomo, una struttura, un letterale, un oggetto od un set di oggetti.
10
Modello computazionale – In un ODBMS, nonostante siano possibili interrogazioni dichiarative,
l’interfaccia primaria per la creazione e la modifica di oggetti è direttamente la sintassi del
linguaggio nativo. Inoltre, ad ogni oggetto nel sistema viene assegnato un identificatore (OID) che è
unico ed immutabile durante la vita dell’oggetto. Un oggetto può contenere un OID che referenzia
logicamente o punta un altro oggetto. Queste referenziazioni dimostrano la loro preziosità quando
vengono associate ad oggetti con entità del mondo reale. Esse formano anche la base di alcune
caratteristiche quali le relazioni bi-direzionali e gli oggetti composti. Nella maggior parte degli
ODBMS gli OID diventano fisici (la referenza logica viene convertita in un puntatore ad uno
specifico indirizzo di memoria) una volta che il dato viene caricato in memoria per essere usato
dall’applicazione. Questa conversione, che viene chiamata pointer-swizzling, permette l’accesso
agli oggetti memorizzati alla velocità di accesso della memoria a differenza degli approcci
tradizionali che richiedono più tempo.
Nella maggior parte delle implementazioni un oggetto è un’istanza di una classe. Una classe
definisce il comportamento e lo stato dei suoi oggetti. Lo stato è definito dalla stato dei valori dei
suoi attributi. Il comportamento è definito da un insieme di metodi o funzioni in linguaggio
tradizionale.
2.2 Introduzione a SQL
SQL (Structured Query Language) è un linguaggio per la gestione delle basi di dati (database)
fondato sulle teorie del modello relazionale.
La potenza descrittiva di SQL dipende dal fatto che il suo vocabolario include un numero di
istruzioni piuttosto limitato, ma al tempo stesso molto flessibile. Del resto è giusto che sia così: una
sintassi complicata e con troppe istruzioni comporta sforzi per ricordarla, non agevolando affatto lo
sviluppo e l’implementazione delle interrogazioni alle strutture dati. In contrasto con i linguaggi
tradizionalmente più complicati, SQL esce agevolmente dalla mischia e si rileva il linguaggio ideale
per i database relazionali.
Come tutti i linguaggi che si rispettino, anche SQL ha seguito un iter di standardizzazione.
L’istituto che si è occupato di questi aspetti è l’ANSI (American National Standard Institute, Istituto
Nazionale Americano per la Standardizzazione) che sviluppa e pubblica standard industriali e
rappresenta l’ISO (International Organization for Standard) negli Stati Uniti.
2.2.1 Storia di sql e panoramica del linguaggio
Nel 1987 il comitato ISO adottò la prima versione standard di SQL, l’ANSI SQL-86. La versione
successiva standardizzata e utilizzata come riferimento si è avuta nel 1989 (versione ANSI SQL89), mentre le implementazioni di SQL attualmente a disposizione sul mercato fanno riferimento
alla più recente standardizzazione ANSI SQL-92 (che alcuni chiamano semplicemente SQL2) o
addirittura quella che è uscita successivamente (SQL3). Questa versione ufficiale di SQL ha
continuato a seguire l’iter di standardizzazione del comitato ANSI per un certo periodo, ma la
versione successiva è già in studio (SQL4).
Le istruzioni di SQL standard possono essere suddivise essenzialmente in due gruppi: istruzioni per
la definizione delle strutture dati (DDL, Data Definition Language) e istruzioni per la
manipolazione, o modifica, dei dati (DML, Data Manipulation Language). Altre istruzioni
particolari, che dipendono dall’implementazione del database, sono le TCL (Transaction Control
Language); queste permettono di gestire le transazioni. Una transazione è una sequenza di comandi
SQL che il database considera come una singola entità.
Può essere vista come un’unità logica al lavoro.
11
DDL CREATE si usa per creare una struttura con un certo nome secondo le specifiche date, DROP
si utilizza per eliminare una struttura esistente; DML DELETE serve a eliminare le righe specificate
da una tabella, INSERT permette di aggiungere nuove righe in una tabella, SELECT per selezionare
dati dalle righe di una o più tabelle, UPDATE consente di aggiornare i dati nelle righe selezionate di
una tabella; TCL COMMIT serve a confermare le ultime operazioni impartite dopo una transizione
avvenuta; ROLLBACK permette di ripristinare le condizioni precedenti alle ultime operazioni
impostate, SAVEPOINT inserisce un punto si savepoint per annullare solo parte delle modifiche
apportate.
SQL permette essenzialmente di gestire tipi di dato relativi a numeri e a caratteri.
Per quanto riguarda il primo genere, si possono rappresentare numeri esatti (cioè tutti quelli che
sono di tipo intero) o approssimati (le rappresentazioni di numeri con cifre decimali e dotati quindi
di una certa precisione). I tipi relativi ai caratteri, invece, possono consistere in singoli caratteri o
stringhe (sequenze di caratteri di varia dimensione).
SQL permette di impostare vincoli sulle colonne delle tabelle in modo da consentire al DBMS di
memorizzare solo informazioni coerenti con lo schema stabilito. In questo modo ci si svincola da
numerosi controlli che normalmente il programmatore doveva includere all’interno delle procedure
di gestione degli applicativi.
2.2.2 Definizione delle strutture dati e inserimenti
La prima operazione da fare è la creazione della base di dati.
Per creare un nuovo database si usa l’istruzione CREATE DATABASE.
Una tabella è una struttura bidimensionale, nel senso che i dati possono essere individuati
all’intersezione di righe e di colonne. I nomi delle colonne sono in pratica i nomi dei campi, mentre
ogni riga è un record di informazione, ossia un insieme di campi o attributi, anche se non viene
memorizzato fisicamente come i classici record di altri linguaggi.
Quando si desidera creare una tabella, ovviamente la si deve definire dandole un nome e indicando
anche il nome e il tipo dei dati delle relative colonne. Per far questo, si capisce che prima di tutto
occorre pensare attentamente alla forma strutturale della tabella stessa.
Scendendo nei particolari possiamo dire che per risolvere un tipico problema di gestione delle
informazioni attraverso un database, si deve costruire in pratica un insieme di tabelle correlate tra
loro secondo opportuni criteri. La progettazione di un database è piuttosto complessa e richiede un
attento lavoro di analisi. L’analisi è uno studio della realtà che si desidera concretizzare attraverso
archivi ragionati e correlati tra loro. In sintesi, la progettazione del database implica la progettazione
delle tabelle che lo costituiranno e delle relazioni tra le stesse; in pratica, significa rappresentare la
realtà e le relazioni presenti tra i dati scelti. Durante la fase di progettazione si devono scegliere
opportunamente le colonne che serviranno per stabilire le relazioni tra i dati (le chiavi) e si deve
tener conto del processo di normalizzazione. Una chiave primaria (primary key) è una colonna della
tabella (o una combinazione di colonne, nel qual caso si chiama chiave primaria composta) che
permette di identificare univocamente le righe della tabella. Due diverse righe non possono avere
mai lo stesso valore nella primary key e a ogni riga deve corrispondere sempre un valore. La chiave
primaria non può essere nulla.
Una chiave candidata è una colonna (o una combinazione di colonne) che può essere scelta come
chiave primaria. Dopo aver scelto tra le colonne, o tra le combinazioni di esse, la chiave primaria, le
altre diventano di conseguenza chiavi alternative o unique keys. Quindi, anche se in alcune tabelle
possono esserci più colonne candidate a fungere da chiave primaria, una sola viene considerata dal
progettista come primary key.
12
Una chiave esterna (foreign key) è una colonna di una tabella (o una combinazione di colonne) che
fa riferimento a una primary key o a una unique key della stessa tabella o di un’altra tabella (di
solito, comunque, non può far riferimento a una tabella di un database remoto).
Ovviamente si tratta di riferimenti logici e non di puntatori fisici. Il dover mantenere tale
corrispondenza tra queste colonne rientra nella cosiddetta integrità referenziale, che è una
caratteristica fondamentale dei database relazionali. Per tale motivo il vincolo di chiave esterna
viene chiamato anche vincolo di integrità referenziale. Anche in questo caso, se la foreign key fa
parte di una primary key non può essere nulla.
I constraint sono vincoli su tabelle definiti per restringere i valori ammissibili per una colonna o un
gruppo di colonne. Con opportuni vincoli di integrità referenziale, è il RDBMS che si fa carico di
controllare la validità dei riferimenti. Esistono diversi tipi di constraint:
NULL o NOT NULL
UNIQUE
PRIMARY KEY
FOREIGN KEY / REFERENCES
CHECK
Nella CREATE TABLE eventuali constraint possono essere indicati subito dopo il nome della
colonna. Al momento della creazione delle tabelle sarebbe importante definire le relazioni tra le
chiavi. In questo modo il DBMS controlla che vengano inseriti dati collegati nel modo opportuno o
che non vengano cancellati per errore. Se il campo per la chiave è uno solo, è sufficiente digitare
dopo la sua descrizione la parola riservata PRIMARY KEY (per la chiave primaria). Nel caso,
invece, di chiavi composte da più campi, nella CREATE TABLE, dopo la descrizione delle singole
colonne, bisogna specificare il tipo di chiave e tra parentesi la lista dei campi che la costituiscono.
Se si rispetta l’ordine di inserimento dei dati così come sono stati definiti in fase di creazione della
tabella e si inseriscono tutti i campi relativi alle colonne, non è necessario digitare ogni volta il
nome dei campi stessi. Se, invece, si desiderano inserire solo alcuni dati corrispondenti a certi
campi, allora è indispensabile stabilire in quali campi si effettuerà l’inserimento e anche in quale
ordine (che non deve essere necessariamente lo stesso della definizione iniziale della tabella al
momento della CREATE TABLE).
2.2.3 Selezione dei dati
La selezione dei dati si effettua attraverso l’istruzione SELECT. Questa istruzione seleziona alcuni
(o tutti i) dati contenuti nelle tabelle e li visualizza. Non è un caso che SELECT sia la parola più
ricorrente nell’uso di SQL.
L’istruzione SELECT ha diverse parole correlate (clausole):
FROM
WHERE
STARTING WITH
ORDER BY
GROUP BY
HAVING
Un blocco di interrogazione viene chiamato anche query-block. Come si può intuire facilmente,
WHERE è in pratica la seconda parola più ricorrente del linguaggio.
E’ importante ricordare che con SELECT diciamo cosa vogliamo ottenere, ma dobbiamo anche
specificare da dove vogliamo che le informazioni vengano prelevate. E’ possibile avere lo stesso
13
nome per campi di tabelle diverse ed è anche possibile estrarre dati contemporaneamente da due o
più tabelle. Per tali motivi si comprende perché sia indispensabile specificare da quale tabella (o
tabelle) si vogliono prelevare le informazioni. Un campo potrebbe persino risultare vuoto, a meno
che non si forzi il database a controllare che questa condizione non si verifichi. A tal fine è
sufficiente specificare l’opzione NOT NULL in fase di creazione della tabella, indicando quindi che
il campo in questione non può assumere valore nullo. Bisogna però stare attenti a non confondersi:
NULL è diverso dal blank, da uno o più spazi, o da 0 (zero) per i dati numerici. Corrisponde in
pratica alla situazione di non esistenza o di assenza di dati; ecco perché è diverso dallo 0 e dagli
spazi: questi sono considerati dei valori!
Se si effettua un controllo tra un dato qualsiasi e uno NULL, il risultato sarà Unknown, poiché non
è possibile confrontare qualcosa con il nulla. Quindi si può evincere che nei confronti di tipo
boolean esistono tre possibili risultati: TRUE, FALSE e UNKNOWN.
Naturalmente nella query, volendo, si possono specificare anche solo alcuni campi scelti da
visualizzare e non tutti come nell’esempio. Molti analisti, dato che la situazione NULL è scomoda
da gestire preferiscono definire tutti i campi come NOT NULL. Tuttavia esiste un inconveniente
implicito in questa scelta: consiste nel fatto che in fase di inserimento dati, o di modifica della
tabella, è sempre necessario specificare il valore (ad esempio, spazio per i caratteri o 0 per un
NUMBER).
Nelle query si utilizzano spesso gli operatori relazionali:
= Significa ovviamente che il campo deve essere uguale al valore comparato (si legge ‘uguale a’).
Oppure ! = indicano che il campo deve essere diverso dal valore comparato (si legge ‘diverso da’).
NOT indica che l’espressione valutata non deve essere vera
AND indica che entrambe le espressioni a destra e a sinistra dell’operatore devono essere vere
OR indica che deve essere vera una qualsiasi delle due espressioni o entrambe
< Significa che il campo deve essere minore di quello comparato (si legge ‘minore di’).
> Significa che il campo deve essere maggiore di quello comparato (si legge ‘maggiore di’).
<= Significa che il campo deve essere minore o uguale a quello comparato (si legge ‘minore o
uguale di’).
>= Significa che il campo deve essere maggiore o uguale a quello comparato (si legge ‘maggiore o
uguale di’).
Un altro operatore molto importante è LIKE, che serve a estrarre quei valori che assomigliano a un
certo schema senza essere identici a esso. Il simbolo di percentuale (%) si usa per indicare un
carattere jolly (o wildcard, in inglese), ossia una sequenza di caratteri qualsiasi. Per visualizzare una
stringa contenente un carattere solo qualsiasi in una data posizione, e non in sequenza, si utilizza il
simbolo di sottolineatura ( _ ) chiamato anche carattere jolly singolo.
Altri operatori sono quelli logici: NOT, AND, OR. Questi operatori vengono calcolati secondo la
priorità indicata in tabella. Spesso può essere necessario avvalersi dell’uso di parentesi per
esprimere meglio le condizioni da valutare. Naturalmente il contrario di Unknown (NOT Unknown)
rimane Unknown. In questo caso il contrario di una cosa sconosciuta non diventa una cosa
conosciuta.
Join
Il join rientra tra le operazioni principali tipiche dei database relazionali, insieme alla proiezione
delle colonne e alla selezione dei record. Molte pubblicazioni tecniche danno definizioni diverse dei
tipi di join. Anche la documentazione ufficiale delle case produttrici di DBMS spiega l’argomento
in modo differente e usa termini diversi per indicare lo stesso tipo di join implementato da altri.
Nel nostro conteso si ritiene utile far comprendere la logica che guida nell’utilizzo del join e il
riferimento alle parole chiave introdotte con la sintassi di SQL versione ANSI-92 (o SQL-92).
14
Se è vero infatti che in SQL ci sono molti modi per operare le stesse query, è anche vero che per
agevolare gli utenti e i programmatori, con le versioni più recenti del linguaggio il comitato ANSI
ha cercato di semplificare la sintassi e di mettere a disposizione termini riservati più precisi,
puntuali e descrittivi. Il prodotto cartesiano (cartesian product) fra due tabelle (o due relazioni in
senso lato) consiste semplicemente in tutte le possibili coppie di ogni record della prima relazione
con ogni record della seconda. Per questo motivo in inglese viene chiamato anche cross join.
Nell’SQL-89 per operare il prodotto cartesiano era necessario specificare la lista delle tabelle
implicate, come nell’esempio che ci apprestiamo a valutare.
La versione ANSI SQL-92 precede, oltre a questo metodo compatibile con la versione precedente,
anche le parole riservate CROSS JOIN che vanno digitate tra i nomi delle tabelle (al posto quindi
della virgola).
Ovviamente in entrambi i casi il risultato è l’insieme delle coppie delle righe delle due tabelle in
questione, con tutti i campi poiché abbiamo scelto l’operatore *.
Spesso il prodotto cartesiano è troppo ridondante rispetto alle necessità di interrogazione, per cui di
solito si opera un’ulteriore discriminazione dei dati attraverso la clausola WHERE. Quando si opera
una query inserendo una condizione si ha in pratica un predicato o condizione di join (join
condition). Il join viene perciò chiamato join di condizione (condition join).
2.2.4 Modifiche ai dati memorizzati
Inserimento di dati
Per inserire i dati si usa l’istruzione INSERT.
Un metodo veloce per popolare una tabella con i dati di un’altra tabella, sempre che questa sia
perfettamente compatibile con la prima. Nel caso non ci fosse una perfetta corrispondenza nella
struttura della tabella, si possono avere problemi. In ogni caso, è molto importante rispettare
l’ordine di inserimento dei dati secondo quello relativo ai campi, che comunque può differire
dall’ordine indicato nella CREATE TABLE.
Modifica di dati
Per aggiornare una tabella si utilizza l’istruzione UPDATE.
Dopo aver indicato quale tabella vogliamo aggiornare dobbiamo indicare quale campo subirà
l’aggiornamento, attraverso il comando SET, e il nuovo valore che dovrà assumere. E’ importante
ricordare che l’operazione di aggiornamento avviene indipendentemente dal contenuto precedente
del campo o dei campi che vogliamo aggiornare. Ovviamente è possibile aggiornare anche più
campi, specificando dopo SET gli assegnamenti da impartire ai rispettivi nomi di campo e per più
record (righe).
Cancellazione di dati
Quando si parla di cancellazione di dati, si può pensare sia a singoli record sia a intere tabelle. Le
istruzioni che prenderemo in considerazione sono DELETE e DROP.
Per cancellare righe (o tuple) da una tabella si utilizza l’istruzione DELETE.
Il sistema dovrebbe rispondere dicendo quante righe sono state cancellate. Per eliminare tutti i dati
da una tabella (tutte le righe) si possono utilizzare i comandi DELETE FROM o DROP TABLE,
con alcune differenze significative. DELETE FROM è un comando che permette di cancellare tutte
le righe di una tabella. In pratica svuota la tabella senza tuttavia modificarne la sua forma
strutturale.
15
Può capitare di voler eliminare una struttura dai nostri archivi. L’eliminazione è consentita
attraverso l’istruzione DROP seguita dal tipo di struttura e dal suo nome.
Se l’operazione è andata bene, il sistema risponderà:
Table dropped.
Si ricordi che non esiste la possibilità di tornare indietro con un comando ROLLBACK dopo
l’istruzione di DROP che elimina fisicamente la struttura oltre che il suo contenuto.
Controllo delle transazioni
Per la maggior parte delle operazioni compiute è possibile tornare indietro eliminando l’ultima
operazione svolta prima di una conferma (un po’ come annullare l’ultima operazione tramite l’undo
dei programmi di grafica o con il comando Modifica - Annulla degli elaboratori testi). Il comando
che consente il ripristino si chiama ROLLBACK. Per confermare che le operazioni effettuate invece
vanno bene si usa il comando COMMIT. Dopo tale comando non è possibile tornare indietro. Dopo
aver impartito un comando come COMMIT o ROLLBACK, è bene verificare quale sia la reale
situazione delle tabelle che stavamo gestendo, per maggior sicurezza.
In effetti, una transazione comincia dopo COMMIT o dopo aver impartito il comando SET
TRANSACTION. L’istruzione ROLLBACK ovviamente annulla le operazioni dell’ultima
transazione eseguita e ripristina i dati come erano prima di iniziare la transazione stessa.
Naturalmente i dati, per essere ripristinati, devono essere memorizzati dal sistema in qualche zona
di memoria apposita. Ma è il sistema di gestione del database che se ne fa carico in modo
trasparente all’utente. L’unica cosa che si può modificare in alcuni DBMS è lo spazio dedicato a
questi segmenti di rollback (rollback segment). Può risultare utile, comunque, inserire punti fermi
all’interno di una transazione per salvare il lavoro svolto fino a quel punto; questo è possibile
attraverso i cosiddetti punti di salvataggio o savepoint. Impartendo una ROLLBACK, si annullano
le operazioni effettuate dopo quel punto particolare.
Gestione dei privilegi
Ogni componente dello schema può essere protetto tramite l’assegnazione di privilegi
(autorizzazioni) ai vari utenti; un privilegio è caratterizzato da:
La risorsa
L’utente che concede il privilegio
L’utente che riceve il privilegio
L’azione che viene consentita sulla risorsa
SQL offre diversi tipi di privilegi, tra cui:
insert: per inserire un nuovo oggetto nella risorsa
update: per modificare il contenuto della risorsa
delete: per rimuovere un oggetto dalla risorsa
select: per accedere al contenuto della risorsa
Per concedere o revocare privilegi si utilizza il costrutto GRANT o REVOKE.
2.2.5 Funzionalità di SQL-3 estese agli oggetti
SQL-3 estende la precedente versione supportando il paradigma a oggetti.
Le estensioni riguardano:
• Dati definiti dall’utente(ADT, row types e distinct types)
• Costruttori per row types e reference types
• Costruttori per collection types(sets, lists, multisets)
• Funzioni definite dall’utente e procedure
• Supporto per large objects(BLOB e CLOB)
In SQL-3 un dato di tipo astratto è definito specificando un insieme di dichiarazioni di attributi che
rappresentano il valore dell’ADT, le operazioni che definiscono l’uguaglianza e l’ordinamento delle
16
relazioni e le operazioni che definiscono il comportamento dell’ADT stesso. Le operazioni sono
implementate da procedure chiamate routines. Gli ADT possono a loro volta essere definiti come
sottotipi di altri ADT. Un sottotipo eredita la struttura del suo supertipo consentendo l’ereditarietà
multipla. Le istanze di ADT possono essere immagazzinate nel database solo attraverso la
memorizzazione in colonne di tabelle.
Esempio:
CREATE TYPE CONTATTO_TYPE AS OBJECT
(NOME VARCHAR2(20),
COGNOME VARCHAR2(20),
INDIRIZZO VARCHAR2(20),
TELEFONO VARCHAR2(15),
FAX VARCHAR2(15),
EMAIL VARCHAR2(15),
CELLULARE VARCHAR2(15),
PROFESSIONE VARCHAR2(20),
DT_NASCITA VARCHAR2(10) )
Una row type è una sequenza di campi coerente con la definizione della tabella. Due row types sono
equivalenti se entrambe hanno lo stesso numero di campi e nella stessa posizione sono dello stesso
tipo. Le row type sono un tipo di dato che rappresenta una riga in una tabella, così che intere rows
possono essere memorizzate in variabili, passate come argomento a routines e ritornate come valore
da funzioni invocate. Una named row type è un tipo row con un nome assegnato. Una named row
type è effettivamente un tipo di dato definito dall’utente con una struttura interna non incapsulata
consistente unicamente dei suoi campi. Una named row type può essere usata per specificare i tipi
delle righe nella definizione delle tabelle. Una named row type può essere usata per definire un
reference type. Il valore di una reference type definita per una specifica row type è unico ed
identifica una sola istanza della row type in tabella. Il valore di una reference type può essere
memorizzato in una tabella e usato per referenziare(puntare) direttamente una row specifica in
un’altra tabella, come l’OID in un modello ad oggetti permette di referenziare un oggetto mediante
un altro.
Lo stesso valore di una reference type può essere memorizzato in rows multiple, permettendo di
condividere la referenziazione tra le rows.
Esempio:
CREATE TYPE DATA AS
(GIORNO VARCHAR2(2),
MESE VARCHAR2(2),
ANNO VARCHAR2(4),
ORA VARCHAR2(5) )
Il valore di una reference type può riferirsi ad una riga in ogni tabella avente righe del tipo della
reference type. Se la clausola SCOPE è specificata nella definizione di una tabella, le reference
sono ristrette a righe in una singola tabella.
L’uso di SCOPE non implica comunque nessuna integrità referenziale.
17
Esempio:
CREATE TYPE APPUNTAMENTO_TYPE AS OBJECT
(OGGETTO VARCHAR2(20),
DESCR VARCHAR2(50),
DURATA VARCHAR2(5),
LUOGO VARCHAR2(15),
DT_APP REF DATA_TYPE,
UTE REF UTENTE_TYPE )
Collection types permettono di avere valori multipli nei campi delle tabelle.
Esempio:
CREATE TYPE LIST_CONT AS TABLE OF CONTATTO_TYPE
I tipi BLOB(Binary Large Object) e CLOB(Character Large Object) vengono definiti per
supportare oggetti di grandi dimensioni. Le istanze di questi tipi sono memorizzate direttamente nel
database(invece che essere mantenute in files esterni).
Esempio:
CREATE TABLE DIPENDENTE
(NOME VARCHAR2(20),
MANSIONE CLOB(3M),
FOTO BLOB(1G) )
Le tabelle possono essere anche estese con sottotabelle. Una tabella può essere dichiarata come
sottotabella di una o più supertabelle usando la clausola UNDER associata alla definizione della
tabella. Quando viene definita una sottotabella, la sottotabella eredità ogni colonna dalla sua
supertabella e possono essere definite colonne aggiuntive.
Esempio:
CREATE TABLE AMMINISTRATORE OF AMM_TYPE UNDER UTENTE
Operation
Le operazioni che possono essere invocate in sql includono operazioni definite sulle
tabelle(SELECT, INSERT, UPDATE, DELETE), funzioni implicitamente definite per gli ADT e
routines o esplicitamente associate agli ADT o definite separatamente.
Le routines associate agli ADT sono definizioni di funzioni per tipi specifici definiti dall’utente.
Le definizioni di funzioni specificano le operazioni sugli ADT e ritornano un singolo valore di un
tipo di dato definito. Le funzioni possono essere o funzioni SQL, completamente definite nello
schema SQL, o funzioni esterne, definite in un linguaggio programmazione standard.
Le funzioni SQL associate agli ADT sono invocate usando o una notazione funzionale o la dot
notation.
18
Esempio:
SELECT OGGETTO, LUOGO, DT_APP.ORA
FROM TAB_APP
WHERE DT_APP.GIORNO = ‘23’AND DT_APP.MESE = ‘5’
AND DT_APP.ANNO = ‘2004’
Le routines(procedure e funzioni) che definiscono aspetti del comportamento degli ADT possono
essere incapsulate all’interno della definizione degli ADT(queste routines hanno accesso agli
attributi privati degli ADT anche se possono essere definite al di fuori della definizione degli ADT.
Un certo numero di routines ha un nome predefinito; per esempio, quando un ADT viene definito,
una funzione costruttore è automaticamente definita per creare una nuova istanza. La funzione
costruttore ha lo stesso nome del tipo creato e non prende parametri in ingresso e ritorna una nuova
istanza del tipo creato i cui attributi sono settati al loro valore di default. La funzione costruttore è
PUBLIC. Inoltre, per ogni attributo, sono automaticamente definite funzioni che settano o ritornano
il valore dell’attributo stesso; queste funzioni possono essere esplicitamente definite in fase di
programmazione. Possono essere definiti anche attributi virtuali: questi non hanno dei valori
memorizzati; il loro comportamento deriva dalle funzioni definite dall’utente che settano o leggono
i loro valori. Possono inoltre essere definite le funzioni di comparazione e ordinamento di ADT. La
conversione tra diversi ADT è permessa mediante la definizione di funzioni di casting.
Esempio:
CREATE FUNCTION Importo_Euro (p IMPORTO)
RETURNING DEC(10,2)
BEGIN
RETURN p/1936.27
END;
Metodi
Una routine SQL è sostanzialmente un sottoprogramma. Una routine può essere una funzione o una
procedura. Una routine legge o aggiorna il valore di un ADT. Una routine è specificata dal nome,
dai parametri in ingresso, dai valori in uscita(se è una funzione) e dal corpo costituito dal codice.
Una routine SQL ha un corpo scritto completamente in SQL. Una routine esterna ha un corpo
scritto in un linguaggio di programmazione.
Stato
SQL-3 supporta lo stato dei valori di vari tipi di dati. Per esempio lo stato di un ADT è la sequenza
ordinata dei componenti dell’ADT memorizzati. Lo stato di una row è l’insieme ordinato dei valori
delle sue colonne; e così via.
Tempo di vita degli oggetti
Un’istanza di un ADT può esistere in ogni punto dove il nome dell’ADT viene referenziato.
Comunque, il solo modo che un ADT ha per essere memorizzato persistentemente in un database è
di memorizzarlo nelle colonne di una tabella.
Esempio:
CREATE TABLE APPUNTAMENTO OF APPUNTAMENTO_TYPE
19
Non esiste un metodo per individuare una singola istanza di un ADT con le estensioni di SQL-3, e
memorizzarla persistentemente nel database usando unicamente il nome. Similmente non c’è un
posto nel quale tutte le istanze di un ADT esistono, a meno che l’utente non lo crei esplicitamente,
definendo una tabella nella quale tutte le istanze vengano memorizzate. Quindi, in SQL-3 non è
possibile applicare interrogazioni(query) a tutte le istanze di un dato ADT. Le istanze devono prima
essere memorizzate in una o più tabelle(come valori di colonna).
Una row in una tabella esiste fino a che non viene cancellata. La cancellazione di una istanza di
ADT è ottenuta cancellando la riga nella quale è contenuta.
Le routines in SQL-3 possono essere specificate all’interno della definizione dell’ADT o
esternamente. SQL-3 supporta un modello a oggetti generalizzato .
Eventi
In SQL un trigger è un costrutto che viene implicitamente attivato ogni volta che l’evento associato
ad esso si verifica. Quando un trigger viene attivato, l’azione specifica viene eseguita se è
soddisfatta la condizione associata.
I triggers possono essere utilizzati per vari scopi, come validazione di dati in ingresso, lettura da
altre tabelle o per messaggi di allerta. Gli eventi che è possibile associare ad un trigger includono
inserimenti, cancellazioni e aggiornamenti di tabelle e colonne. Una condizione associata al trigger
può essere ogni condizione SQL ed una azione può essere ogni istruzione SQL. I trigger possono
specificare quando il trigger dovrebbe essere attivato prima che l’operazione sia lanciata, o dopo.
La condizione e l’azione possono essere eseguite per ogni row(FOR EACH ROW) implicata
dall’istruzione SQL, o solo una volta per l’intero trigger(FOR EACH STATEMENT).
Polimorfismo
Routines differenti possono avere lo stesso nome. Questo prende il nome di overloading, e può
essere richiesto, per esempio, per permettere ad un sottotipo ADT di ridefinire un’operazione
ereditata da un supertipo.
SQL-3 implementa quello che è conosciuto come un modello a oggetti generalizzato, il che
significa che i tipi di tutti gli argomenti di una routine sono presi in considerazione al momento
della determinazione di quale routine invocare, piuttosto che usare un singolo tipo specifico
nell’invocazione come in C++ o Smalltalk. Come risultato, le regole per la determinazione di quale
routine invocare possono essere complesse. L’istanza della routine che viene scelta per l’esecuzione
è quindi la migliore scelta dati i tipi degli argomenti passati a run time.
Incapsulamento
Ogni componente(attributo o funzione) di un ADT ha un livello di incapsulamento che può essere
PUBLIC, PRIVATE o PROTECTED. I componenti public formano l’interfaccia dell’ADT e sono
visibili a tutti gli utenti autorizzati dell’ADT. I componenti private sono totalmente incapsulati, e
sono visibili solo all’interno della definizione dell’ADT che li contiene. I componenti protected
sono parzialmente incapsulati; sono visibili all’interno dell’ADT ed agli eventuali sottotipi
dell’ADT stesso. SQL-3 supporta anche l’incapsulamento per le viste, che vengono considerate
come sottotipo della tabella associata.
Identità, uguaglianza e copia
Di default, il test di uguaglianza tra attributi corrisponde al test di uguaglianza tra due istanze di
ADT. Alternativamente, la specifica della dichiarazione di una funzione di un ADT è usata per
determinare l’uguaglianza tra due istanze di ADT.
20
Due valori non sono uguali se entrambi hanno valore NULL. Due rows(o parti di esse) sono distinte
se almeno uno dei rispettivi campi è diverso. Altrimenti sono identiche. Il risultato del confronto di
due valori o due rows non è mai sconosciuto.
Tipi e classi
La forma più semplice di tipo definito dall’utente di SQL-3 è il distinct type, che permette all’utente
di trattare tipi equivalenti di dati in modo separato. La parola chiave DISTINCT usata nella
dichiarazione indica che il tipo risultante deve essere trattato in modo distinto da ogni altra
dichiarazione dello stesso tipo.
Ogni tentativo di trattare un’istanza di un tipo come un’istanza di un altro terminerà in un errore
anche se ogni tipo ha la stessa rappresentazione.
Ereditarietà e deleghe
Un ADT può essere definito come sottotipo di uno o più ADT attraverso la clausola UNDER.
In questo caso, l’ADT diventa un sottotipo dell’ADT specificato nella clausola UNDER.
Un tipo può avere più di un sottotipo e più di un supertipo. Un sottotipo eredità tutti gli attributi e il
comportamento dei suoi supertipi; attributi e comportamenti addizionali possono essere definiti.
Un’istanza di un sottotipo è considerata un’istanza di tutti i suoi sottotipi. Un istanza di un sottotipo
può essere usata ogni volta che un’istanza di un suo supertipo è prevista.
Ogni istanza è associata con il tipo più specifico che corrisponde al più basso sottotipo associato
all’istanza. In un dato istante, un’istanza deve avere esattamente un tipo specifico(in alcuni casi
l’ereditarietà multipla deve essere usata per assicurare che questo sia vero). Il tipo più specifico di
un’istanza non ha bisogno di essere necessariamente l’ultimo nodo dell’albero delle gerarchie. Un
predicato TYPE permette all’istanza di un ADT di essere testata a runtime.
Una definizione di un sottotipo ha accesso alla rappresentazione di tutti i suoi supertipi, mentre non
ha accesso ai suoi sottotipi. Effettivamente, i componenti di tutte le rappresentazioni di supertipi
sono copiate nella rappresentazione dei sottotipi con lo stesso nome e tipo di dato. Per evitare
conflitti di nome, un sottotipo può rinominare componenti di una rappresentazione ereditata dal suo
supertipo.
Un supertipo può definire operazioni come ogni altro ADT. Un sottotipo può anche definire
operazioni che hanno lo stesso nome delle operazioni definite per gli altri tipi, inclusi i suoi
supertipi(overriding).
Una famiglia di sottotabelle deve avere al massimo una supertabella. ad ogni riga di una sottotabella
deve corrispondere esattamente una riga della supertabella. Viceversa ad una riga di una
supertabella corrispondono più righe di una sottotabella.
Le regole per le istruzioni SQL(INSERT, DELETE, UPDATE) sono definite in modo da tenere le
righe in sottotabelle consistenti con ognuna delle altre; specificatamente:
Se una riga è inserita in una sottotabella T, allora una riga corrispondente( con lo stesso
identificatore e lo stesso valore di ogni colonna della sottotabella) è inserita in ogni supertabella di
T seguendo la gerarchia delle tabelle. Se T non ha supertabelle, una riga è inserita solo in T.
Se una riga è aggiornata in una supertabella, allora tutte le righe corrispondenti alle sottotabelle
sono aggiornate.
Se una riga è aggiornata in una sottotabella, allora ogni riga corrispondente è aggiornata ai nuovi
valori.
Se una riga in una tabella appartenente ad una famiglia di sottotabelle è cancellata, allora ogni riga
corrispondente è cancellata.
21
Relazioni
Le relazioni(tabelle) possono essere usate per definire relazioni n-arie come in SQL92; l’integrità
referenziale così come altri vincoli possono essere definite in queste tabelle. Le colonne i cui tipi
sono reference type permettono anche la modellizzazione delle relazioni in SQL-3. la
referenziazione a gruppi di oggetti può essere specificata usando righe contenenti istanze di
collection type (multiset, list, set) di SQL-3.
Attributi
Ci sono due tipi di attributi in un ADT: attributi memorizzati(stored) ed attributi virtuali(virtual).
Un attributo memorizzato è specificato mediante un nome e un tipo di dato. Il tipo di dato di questo
attributo può essere ogni tipo di dato conosciuto incluso un altro ADT. Ogni attributo memorizzato
dichiara implicitamente un paio di funzioni: get(che ritorna il valore) e set(che setta il valore).
Un attributo virtuale ha un valore che è derivato o computato da una funzione definita dall’utente.
Le colone di tabelle possono anche essere usate per rappresentare attributi come in SQL92.
Letterali
In SQL-3 i letterali sono usati per specificare valori non nulli. Gli ADT non hanno valori letterali.
Row type letterali sono formati concatenando valori da colonne singole.
Contenimento
SQL-3 supporta il concetto di valori contenuti in altri valori o altri ADT. Una forma di
contenimento semantico può essere implementata specificando triggers che forzano la
manipolazione in cascata di una collezione di struttura di dati quando uno di questi viene
manipolato. Questo tipo di contenimento deve essere specificato dall’utente.
Aggregati
SQL-3 supporta row type come strutture letterali. Istanze di row type possono essere usate come
valori in tabelle; le row type possono anche essere nestate. Un numero di collezioni parametrizzate
predefinite sono anche definite. Una collezione deve essere specificata come un SET(<type>),
MULTISET(<type>) o LIST(<type>). In ogni caso, il parametro <type> (chiamato element type)
può essere un tipo predefinito, un ADT, una row type, o un’altra collection type. Un element type
non può essere un reference type, ne può essere un named row type contenente un campo il cui tipo
è reference type.
Una collezione può essere usata come una semplice tabella in interrogazioni. In questo caso, ogni
elemento della collezione corrisponde ad una riga nella tabella. La tabella viene trattata come se
avesse una singola colonna il cui tipo è definito dal tipo dall’istanza della collezione. Siccome le
collection type sono tipi di dato, esse devono essere dichiarate come dei tipi di colonne di tabelle
per essere persistentemente memorizzate nel database.
Estensibilità
Nuove tabelle e tipi(ADT, row types, collection type, etc.) possono essere definiti su tipi esistenti.
I tipi esistenti possono essere modificati aggiungendo nuove operazioni, attributi o vincoli.
Le istanze esistenti non possono acquisire o perdere tipo senza la creazione di una nuova istanza e
la distruzione di quella vecchia.
Dinamicità
Sono possibili limitate evoluzioni dello schema delle tabelle applicando la clausola ALTER. Le
azioni che possono essere eseguite usando la clausola ALTER includono aggiunta, variazione, e
eliminazione di colonne e aggiunta ed eliminazione di supertabelle e vincoli su esse. I tipi di dati
possono anche essere aggiunti ed eliminati.
22
Metaclassi/ metaoggetti
SQL-3 non ha nozioni di metaclassi e la sua semantica non è estensibile.
Linguaggi ad oggetti
Nuove istruzioni sono state aggiunte in SQL-3 per fare in modo da poter specificare completamente
il comportamento degli oggetti attraverso il linguaggio SQL. Alcune istruzioni aggiunte includono:
Una istruzione di assegnamento che permette al valore ritornato da una espressione SQL di essere
assegnato ad una variabile locale, ad una colonna o ad un attributo di un ADT.
Una istruzione CALL che permette di invocare una procedura SQL.
Una istruzione RETURN che permette al valore di una espressione SQL di essere ritornato come
valore di ritorno di una funzione SQL.
Una istruzione CASE che permette la selezione di un percorso di esecuzione di blocchi di istruzioni
SQL basato su scelte alternative.
Una istruzione IF con THEN,ELSE, ELSEIF che permette la selezione di un percorso di esecuzione
basato sul valore di una o più condizioni.
Istruzioni per LOOP, WHILE e REPEAT che permettono la ripetizione di un blocco di istruzioni
SQL.
Controlli addizionali includono istruzioni composte e trattamento delle eccezioni. Un’istruzione
composta è un’istruzione che permette di raggruppare in un blocco(block) una collezione di
istruzioni SQL. Un’istruzione composta può dichiarare delle sue variabili locali e specificare delle
eccezioni per gestire eventuali errori che si verificano durante l’esecuzione di ogni istruzione
all’interno del gruppo. Per ogni eccezione, una dichiarazione condizionale stabilisce una
corrispondenza uno a uno tra SQLSTATE e l’eccezione definita dall’utente.
Lo standard SQL92 definisce l’interazione con un certo numero di linguaggi standard. Un aspetto
chiave dell’interazione del linguaggio è la definizione della corrispondenza tra tipi di dati SQL e
tipi di dati del linguaggio. In alcuni casi, questa corrispondenza è relativamente semplice; per
esempio, il tipo di dato CHARACTER di SQL viene mappato sul tipo CHAR di C. In altri casi la
mappatura non è immediata; per esempio, SQL92 supporta il tipo di dato TIMESTAMP, ma i
linguaggi di programmazione standard non hanno un tipo di dato equivalente. In questi casi, SQL
richiede l’uso di una funzione di cast per convertire il tipo TIMESTAMP al tipo CHAR a livello di
programma e viceversa. Non ci sono invece tipi corrispondenti definiti per le strutture come ad
esempio una riga di una tabella e un record o struttura o linguaggio di programmazione.
2.3 Introduzione allo standard ODMG
ODMG(Object Database Management Group) e' un consorzio di industrie(O2, Object Design,
Objectivity, Ontos, Versant, Poet, Servio, HP,Itasca, ....) istituito nel '91 per redigere uno standard
con l’obiettivo di favorire la portabilità del software.
ODMG 3 e' l'evoluzione di tre precedenti versioni. La prima versione, ODMG93, è dell'inizio '94.
Il consorzio è affiliato al gruppo parallelo OMG, il quale si occupa di object orientation in generale.
La caratteristica peculiare dello standard ODMG3 è l’integrazione delle funzionalità dei DBMS e
dei linguaggi di programmazione object oriented in modo che gli oggetti della base dati appaiano a
tutti gli effetti anche come oggetti del linguaggio di programmazione senza DMLintermediari.
23
2.3.1 Storia dello standard
•
•
•
•
1991 nasce lo standard ODMG in conseguenza all’apparizione sul mercato dei primi
OODBMS
1993: ODMG93
1997: ODMG 2.0
1999: ODMG 3.0
2.3.2 Architettura dello standard
Il modello a oggetti dello standard ODMG3 è direttamente derivato dal modello proposto da OMG
con l’aggiunta di poche caratteristiche necessarie alla base di dati (Fig. 2-3).
Similmente a SQL3, ODMG3 definisce un linguaggio per la specificazione di oggetti(ODL)
indipendente dai vari linguaggi di programmazione ed un linguaggio per l’interrogazione funzionale
della base di dati a oggetti(OQL) ispirato allo standard SQL.
Fig. 2-3. Architettura
2.3.3 Modello dei dati
Il modello dei dati di ODMG3 è fortemente tipizzato; tutti gli elementi di un dato tipo condividono
il medesimo range di valori di stato (stesso insieme di proprietà) e un comportamento comune
( stesse operazioni).
Tutti i tipi dichiarabili in ODMG sono caratterizzati da:
• una specifica esterna (stato e comportamento astratti);
• una implementazione (stato e comportamento concreti).
La specifica esterna si articola in:
• aspetti statici (proprietà o variabili di stato);
• aspetti dinamici a loro volta suddivisi in:
operazioni ammesse sulle proprietà;
eccezioni sollevate dalle operazioni.
24
Nell’attuale standard l’implementazione degli aspetti sia statici sia dinamici è delegata al “binding”
con uno specifico linguaggio (C++, Java, Smalltalk,...).
I tipi semplici dichiarabili sono i letterali, i quali non hanno identificatori e sono categorizzati in:
Atomici: long, short, unsigned long, unsigned short, float, double, boolean ,octet, char(carattere),
string, enum(enumerazione);
Collezioni parametriche: set<t>, bag<t>, list<t>, array<t>, dictionary<t,v>;
Strutturati: date, time, timestamp, interval, struct .. {..}.
Anche gli oggetti sono categorizzati in tipi; ciascun oggetto, a differenza dei letterali, possiede un
unico identificatore; per questo motivo un letterale (senza identificatore) è detto immutabile mentre
un oggetto (con identificatore) è detto mutabile.
il comportamento è definito da un insieme di operazioni e lo stato dai valori delle rispettive
proprietà suddivise in attributi e relazioni.
Le proprietà ed il comportamento definiscono le caratteristiche di un oggetto.
Gli oggetti di un dato tipo esibiscono lo stesso comportamento e condividono lo stesso spazio degli
stati.
I tipi degli attributi di un oggetto possono essere Literal od Object.
Gli attributi di una “Interface” non sono una struttura (struct) in quanto l’interfaccia contiene solo
operazioni. Gli eventuali attributi sono forme contratte delle due funzioni get e set.
Tuttavia la classe che eredita l’attributo deve ridefinirlo come tale o come funzione.
Un attributo non è un oggetto e non si possono definire attributi di attributi.
Un attributo il cui tipo è un oggetto è una associazione monodirezionale.
Le associazioni, come nell’ER, sono di tipo 1- 1, 1 - N, N - M, binarie e prive di attributi. Le
associazioni possono essere definite solo tra oggetti.
Esempio:
Class Appuntamento relationship Utente ute
L’integrità referenziale deve essere garantita dal sistema.
La cardinalità N è realizzata da collezioni LITERAL.
L’associazione non è un oggetto e non possiede proprietà.
L’attraversamento di un’associazione nella direzione “molti” è governato
dalle primitive della collezione che la definisce.
L’implementazione delle associazioni può essere facilitata se macro espanse secondo il seguente
schema raccomandato da ODMG:
A) Cardinalità 1
relationship X y inverse Z ;
attribute X y; //Variabile gestita da form_ e drop_
void form_y(in X un_x) raises(IntegrityError);
void drop_y(in X un_x) raises(IntegrityError);
Le procedure devono garantire l’integrità referenziale (side effect).
25
Esempio:
class Impiegato …….. {……...
relationship Manager manager inverse Manager::subalterni;…. }
class Impiegato …….. {……...
attribute Manager manager ;
void form_ manager (in Manager m ) raises(IntegrityError);
void drop_ manager (in Manager m ) raises(IntegrityError);…. }
B) Cardinalità N
relationship set<X> y inverse Z ;
readonly attribute set<X> y;
void form_y(in X un_x) raises(IntegrityError) ;
void add_y(in X un_x) raises(IntegrityError) ;
void drop_y(in X un_x) raises(IntegrityError);
void remove_y(in X un_x) raises(IntegrityError);
Esempio:
class Manager …….. {………
relationship set<Impiegato> subalterni inverse Impiegato::manager... }
class Manager …….. {……...
readonly attribute set<Impiegato> subalterni;
void form_ subalterni(in Impiegato imp ) raises(IntegrityError) ;
void add_ subalterni(in Impiegato imp ) raises(IntegrityError) ;
Per quanto riguarda il comportamento degli oggetti, le operazioni sono definite con la sintassi
CORBA, uno standard prodotto dall’OMG per favorire l’interoperabilità del software:
<tipo_risposta> <nome_op> (in | out | inout <Tipo_par1> <parametro1>, …)
Ogni nome di operazione deve essere unico in un dato tipo; inoltre tipi diversi possono avere metodi
omonimi (overloading di nome). Quando è richiamato un metodo su un oggetto viene selezionato
quello specifico del tipo di quell’oggetto (semantica dell’operazione delegata all’implementazione,
metodo). Una operazione può produrre side_effect.
Il tipo di un oggetto può essere dichiarato con due meccanismi: interface o class; interface definisce
l’oggetto tramite il suo comportamento astratto. E’ un approccio funzionale: tutte le proprietà
(attributi, relazioni, operazioni) sono dichiarazioni di altrettante funzioni applicabili all’oggetto.
Il tipo interface non può istanziare oggetti.
Class definisce invece l’oggetto avvalendosi degli aspetti sia statici sia dinamici; inoltre è possibile
istanziare oggetti di tipo class.
Interface può essere ereditata da una classe per istanziare oggetti con il comportamento descritto
dalle operazioni dell’interfaccia.
Proprietà astratte (attributi e relazioni) di “Interface” devono essere ridefinite nella
classe per implementarle sottoforma di attributi statici. (Una proprietà di “Interface” è una forma
contratta delle due funzioni get e set,)
L’Implementazione di un dato tipo di oggetto, specificato da “class”, consiste in:
- una rappresentazione degli aspetti statici;
- metodi abbinati ad operazioni definite nella classe o ereditate da una “Interface”;
26
in questo modo la separazione netta tra specifica esterna ed implementazione favorisce
l’incapsulamento ed una molteplicità di implementazioni differenti
Le classi e le interfacce possono essere in relazione gerarchica.
Esempio:
Interface Persona {…..}
Interface Dipendente:Persona {…..}
Interface Amministratore:Dipendente {…..}
Si può dichiarare una classe in gerarchia con una interfaccia.
Esempio:
Class Utente:Persona {…..}
In questo modo si possono istanziare oggetti della classe Utente con il comportamento
dell’interfaccia Persona.
L’estensione Extent (ammissibile solo nelle classi) di una classe è l’insieme di tutte le istanze del
tipo abbinato alla classe all’interno di una particolare base di dati.
Se un oggetto è istanza della classe A allora appartiene all’estensione di A.
Se B è sottoclasse di A allora l’estensione di B è inclusa nell’estensione di A
La creazione dell’estensione di una classe è a carico dell’utente. (Si noti che l’estensione di una
tavola relazionale è automatica);le estensioni possono avere indici.
Chiavi
Come per SQL possono essere semplici (un solo attributo) oppure composte (più attributi racchiusi
tra parentesi rotonde).
Identificazione
Univoca nell’ambito di una base di dati.
Nomi
Ad ogni oggetto istanziato è attribuibile uno o più nomi simbolici per accedervi via programma o in
interattivo. Gli oggetti con nome sono di norma usati quali entry point della base di dati, ad esempio
nomi di estensioni. I nomi sono simili alle variabili globali dei linguaggi di programmazione.
Ciclo di vita degli oggetti
Transienti, memoria rilasciata a fine programma.
Persistenti, memoria gestita dal ODBMS.
Il ciclo di vita è indipendente dal tipo.
(E’ una differenza di fondo rispetto al modello relazionale).
L’indipendenza dal tipo implica che le stesse operazioni agiscono indifferentemente su oggetti
persistenti e transienti.
(In relazionale i dati persistenti sono gestibili solo via SQL).
Struttura delle dichiarazioni Interface e class in ODL
(Object Definition Language)
Alcune clausole sono opzionali:
class <nome> [extends <superclasse>
27
[ : <interfaccia>:...]]
(extent <nome della collezione>
keys eventuali chiavi )
{ attributi;
relazioni; 1-1, 1-n, n-m
operazioni;
eccezioni
}
interface <nome> [ : <interfaccia>:….]
{ attributi;
relazioni; 1-1, 1-n, n-m
operazioni;
eccezioni
}
L’ereditarietà in ODL
Una classe eredita (extends) da al più una classe (ereditarietà semplice);
Una classe può ereditare da più interfacce (:<interface>:... ereditarietà multipla, ma con il vincolo
che le interfacce non contengano operazioni omonime);
Le operazioni di una superclasse appaiono con la stessa segnatura (nome, tipo parametri e tipo
risultato) nella sottoclasse;
Il metodo (body) di una operazione ereditata può essere ridefinito.
28
Capitolo 3 Confronto tra i vari DBMS
3.1 Differenze tra i vari DBMS
La scelta riguardo a quale tipo di DBMS utilizzare per diverse applicazioni si basa anche sulla
valutazione di alcuni importanti aspetti tra cui:
•
•
•
•
•
•
•
•
•
•
•
Supporto per i linguaggi di programmazione Objcet Oriented
Semplicità d’uso
Semplicità di sviluppo
Estensibilità
Complessità delle relazioni
Distribuzione e replicazione e federazione
Maturità della tecnologia
Esperienza dei programmatori e universalità di SQL
Tecnologie proprietarie
Applicabilità
Trasparenza
Supporto per i linguaggi di programmazione Object Oriented
Gli ODBMS sono stati ottimizzati per un supporto diretto con le applicazioni Object Oriented. Tutti
i concetti OO sono supportati(ad esempio incapsulamento, ereditarietà, polimorfismo). Il modello
ODBMS è congruente con il modello ad oggetti dell’applicazione OO. Siccome le relazioni sono
direttamente rappresentate, l’integrità referenziale è mantenuta dall’ODBMS. Il modello a oggetti
usato dall’Object Database Management Group nello standard ODMG-93 è derivato dall’OMG
Common Obect Model, con l’aggiunta dell’interazione con linguaggi tipo C++, Smalltalk e Java.
Il modello a oggetti di SQL-3 è per sua definizione, un compromesso che aggiunge qualche
supporto agli oggetti mentre mantiene la compatibilità con SQL-2. Gli ORDBMS hanno un
supporto limitato per l’ereditarietà, senza una definizione consistente tra i produttori e il rispetto
dello standard SQL-3. Per una applicazione OO che utilizza relazioni complesse per lavorare con un
database relazionale o Object-relational, il codice deve essere scritto per mappare la complessa
struttura a oggetti nel semplice modello del database relazionale. L’analogia sarebbe quella di
smontare completamente la macchina prima di parcheggiarla in garage ogni notte per poi
riassemblarla ogni mattina. Questo ha effetti sia sullo sviluppo sia sulle performance
dell’applicazione. il codice scritto per gestire la mappatura può risultare consistente rispetto a tutto
il codice dell’applicazione. Il mantenimento dell’applicazione degli ODBMS risulta anche più
semplice rispetto agli altri tipi di DBMS. A runtime, le carenza di performance sono pagate
muovendo i dati tra il database e l’applicazione. siccome questa mappatura dal db all’applicazione è
lasciata all’applicazione, piuttosto che al DBMS, c’è il rischio della violazione d’integrità.
Applicazioni differenti possono mappare in modo diverso creando inconsistenze.
Semplicità d’uso
I database relazionali, con le loro tabelle, righe e colonne, risultano una facile interfaccia per
l’utente. Comunque, sono pochi gli utenti che usano il linguaggio SQL direttamente. I produttori di
database relazionali hanno sviluppato dei tools che nascondono all’utente SQL e lo generano in
background. Per quanto riguarda i database a oggetti, ci sono molti meno tools anche se si prevede
29
un aumento in futuro. Questo modello di tabelle con tipi di dati semplici è facile da usare, ma
solamente se esso mappa in modo ottimale le strutture dati delle applicazioni. Questo approccio
tradizionale ha portato ad una specializzazione dei programmatori di database che hanno acquisito
esperienza nella mappatura da tabelle alle strutture delle applicazioni. I programmatori di database a
oggetti, invece, trovano semplice usare direttamente gli oggetti senza forzarli in tabelle.
Semplicità di sviluppo
I database a oggetti trovano una piena applicazione nella programmazione object oriented. Infatti,
questi database furono sviluppati per consentire una corrispondenza diretta tra l’applicazione OO e
gli oggetti persistenti nel database. Il paradigma dello sviluppo orientato agli oggetti ha il vantaggio
di essere una delle vie più naturali per modellizzare il mondo reale. Gli oggetti nel mondo reale
vengono modellizzati direttamente uno ad uno nel software. Questa corrispondenza semplifica
notevolmente lo sviluppo in tutto il ciclo di vita dell’applicazione e migliora il suo mantenimento.
Essa semplifica anche l’integrazione di tools di produttori differenti attraverso le fasi del ciclo di
vita del software. Il modello RDBMS implica una indipendenza dai dati del database rispetto a
quelli dell’applicazione. Con SQL come linguaggio di interrogazione, ogni applicazione può
accedere ed usare i dati in un modo indipendente. Questa procedura riduce i costi di mantenimento,
in quanto ogni nuova applicazione non richiede la modifica del database anche se le nuove
applicazioni hanno specifiche addizionali.
Estensibilità
L’uso tradizionale dei DBMS è stato limitato dal numero esiguo dei tipi di dati(string, integer,
floating point, number, date, currency) supportati dal sistema. Per gli ORDBMS, estensibilità
significa che agli utenti è permesso definire nuovi tipi di dati. In ogni caso, per gli ORDBMS
esistono un numero di vincoli, i quali devono essere presi in considerazione dagli sviluppatori
quando utilizzano gli ADT. Per esempio, le reference possono essere usate per referenziare una riga
in una tabella, ma la row type deve essere di tipo named. Quindi, c’è un trade-off tra il vantaggio di
una veloce referenziazione rispetto all’estensibilità degli ADT. Gli ODBMS sono estensibili perché
le classi definite nell’applicazione possono essere definite da nuovi tipi persistenti. Nuove classi
possono essere aggiunte dagli utenti con tutte le funzionalità del DBMS per le istanze persistenti di
quelle classi.
Complessità delle relazioni
Le applicazioni, qualche volta, hanno delle relazioni di tipo molti a molti. Siccome gli ODBMS
usano gli OID, essi sono più opportuni per le applicazioni che hanno da processare relazioni
complesse. Questo perché risulta più semplice navigare tra reference successive, relazioni molti a
molti bi-direzionali e propagazione di operazioni attraverso relazioni per formare oggetti composti.
Gli ORDBMS supportano scarsamente queste capacità. La modellizzazione delle relazioni potrebbe
richiedere tabelle addizionali in un RDBMS. Il processamento di solito include join multipli che
richiedono risorse maggiori.
Distribuzione, replicazione e federazione
Un database distribuito memorizza i suoi dati trasparentemente attraverso volumi multipli ed anche
differenti locazioni. Un database replicato ha tutte o porzioni dei suoi dati replicati in uno o più
differenti luoghi e periodicamente sincronizza i contenuti dei suoi dati replicati. La replicazione dei
dati è la base dell’immagazzinamento dei dati . Un database federato è un’unione logica tra
database distinti ognuno in esecuzione su server indipendenti.
30
Nonostante gli RDBMS permettono ai server di comunicare con altri server e possono supportare
differenti livelli di replicazione, gli ODBMS supportano una forma di distribuzione e replicazione
aggiuntiva con una completa trasparenza attraverso server multipli e database federati, schemi
multipli in una gerarchia, replicazioni con sincronizzazione automatica ed integrità. In aggiunta, gli
ODBMS supportano funzionalità non presenti negli RDBMS, come l’evoluzione degli schemi
dinamici con la migrazione automatica dell’istanza.
Alcuni ODBMS supportano anche la memorizzazione ed il rintracciamento distribuito. Sia il
partizionamento orizzontale (ogni classe è definita in ogni database) che quello verticale (alcune
classi sono in un database, altre in un altro) possono essere supportati. La memorizzazione
distribuita permette di usare specifiche politiche, come Round Robin, per memorizzare oggetti in
differenti database fisici. Il rintracciamento distribuito significa che sono supportate delle query
parallele. La distribuzione è una caratteristica fondamentale nel momento in cui è necessario il load
balancing.
Maturità della tecnologia
Gli RDBMS sono stati sviluppati ed usati per più tempo rispetto ai database ad oggetti, quindi
risultano essere una tecnologia più matura. I prodotti più maturi sono stati messi a punto per
ottimizzare le performance e supportare un largo insieme di funzionalità, includendo il supporto per
funzionalità avanzate quali processamento parallelo, replicazione, alta disponibilità, sicurezza e
distribuzione. Esiste un’ampia varietà di tools e applicazioni che supportano gli RDBMS e lavorano
con SQL. Apparentemente, gli ORDBMS dovrebbero trarre vantaggio da questo in quanto sono
estensioni degli RDBMS. Il supporto per gli ADT richiede nuove capacità nel motore del DBMS,
come il recupero, la concorrenza, l’indicizzazione e il caching; quindi questi tipi di dati non
beneficiano automaticamente della maturità del RDBMS.
Gli ODBMS stanno tuttora maturando con più vantaggi rispetto agli RDBMS. Inoltre sarà difficile
per gli ORDBMS essere estensibili e conservare i loro vantaggi dovuti all’esperienza.
Infine, mentre gli ORDBMS evolvono per supportare più funzionalità rispetto agli ODBMS, essi
saranno basati su nuove estensioni della tecnologia diventando perciò la nuova, non sperimentata
tecnologia confrontata con gli ODBMS che sono già maturi in queste aree con il motore del DBMS
progettato nativamente per gli oggetti. Inoltre, nonostante gli ORDBMS provino ad estendere le
architetture ereditate e l’implementazione del modello dei dati, i benefici degli ODBMS trovano
fondamento dal supporto diretto degli oggetti.
Esperienza dei programmatori e universalità di SQL
Un vantaggio degli RDBMS e degli ORDBMS è la disponibilità di esperienza da parte degli
sviluppatori e il grande numero di tools e supporti bibliografici. SQL è il linguaggio più universale
dei database. Come risultato degli investimenti fatti dalle organizzazioni negli ultimi anni, la
maggior parte degli sviluppatori ha familiarità con SQL e hanno tools con i quali sviluppano. Il
meccanismo di accesso mediante ODBC minimizza il costo dell’adozione delle estensioni o delle
nuove funzionalità dl database. Molti ODBMS, quindi, supportano almeno qualche funzionalità di
SQL, ed alcuni le supportano tutte incluse le estensioni per supportare le query di oggetti usando
metodi, relazioni, ereditarietà ed altro. Questo permette agli utenti degli RDBMS di iniziare ad
usare gli ODBMS attraverso il familiare SQL e tools grafici, condividere gli stessi oggetti creati in
Java o C++ e apprendere graduatamente a trarre vantaggio delle capacità aggiunte degli oggetti.
Tecnologie proprietarie
Le architetture di prodotto hanno un impatto diretto sulla strategia dei venditori. Un’architettura più
aperta, possibilmente con API pubblicate e portabile attraverso varie piattaforme, crea opportunità
31
per altri potenziali partners di espandere il mercato. Di contro, un produttore di database desidera
prevenire l’entrata di altri competitori che estendano i suoi prodotti. Nonostante i produttori
incorrano in costi addizionali(e rischi tecnici) per supportare una propria tecnologia , i suoi partners
possono lavorare sinergicamente per creare un mercato che è più grande e si espande più
rapidamente. La questione è il controllo della definizione del prodotto e il controllo dell’evoluzione
di tutte le possibili soluzioni previste nel contesto della tecnologia proprietaria.
Prendendo come esempio Illustra, Informix è occupato a creare un software attorno al suo Universal
Server. Dozzine di venditori hanno sviluppato tools per estendere le capacità disponibili.
IBM invece ha utilizzato un approccio più cauto, scegliendo di essere l’unico provider di DB2.
Applicabilità
Per certe applicazioni gli ODBMS sono sicuramente superiori rispetto agli RDBMS o ORDBMS.
Malgrado questo vantaggio molte organizzazioni ritengono più sicuro usare un database relazionale
perché i produttori di RDBMS sono da più tempo sul mercato e offrono un’esperienza che i
produttori di ODBMS non hanno. Infatti, a parte la Computer Associates, tutti i produttori di
ODBMS non hanno raggiunto una grande dimensione. Comunque, essi hanno formato l’Object
Datatabase Management Group e pubblicato uno standard(ODMG) per gli ODBMS per assicurare
un grado di portabilità tra produttori che usano un ODBMS.
Inoltre, il maggior rischio per gli utenti è continuare a provare nuove applicazioni su gli RDBMS.
Trasparenza
Per quanto riguarda gli ODBMS, la trasparenza è un modo di memorizzare e rintracciare gli oggetti
in un database senza una query esplicita. Ogni volta che si usa la referenziazioni ad un oggetto, se
quell’oggetto non è già in memoria, verrà automaticamente reso dal server. Ma, ogni volta che
viene modificato lo stato dell’oggetto, verrà aggiornato nel database al successivo commit, senza
necessità di parafrasare il codice java con il codice del database. In un ORDBMS, invece, la
trasparenza viene a mancare in quanto sta allo sviluppatore aggiornare le associazioni attraverso i
comandi SQL(INSERT, UPDATE).
3.2 Panoramica dei prodotti in commercio
In Tab. 3-1 sono riassunti i principali produttori di DBMS con specificato il tipo (R, OR, OO) e la
versione.
Tab. 3-1. Prodotti in commercio
Produttore
Oracle
Sybase
Informix
RDBMS
Oracle 7.x
System 10/11
Dynamic Server
IBM
DB/2
UniSQL
Unisys
Computer Associates
Gemstone
O2
OpenIngres
ORDBMS
Oracle 8.x, 9i, 10G
ODBMS
Universal
Server(Illustra)
Universal
Database(DB/2
Extenders)
UniSQL/X
OSMOS
Jasmine
Gemstone
O2
32
Object Design
Objectivity
Versant
Postgree
Object store
Objectivity/DB
Versant ODBMS
Postgree
3.3 Criteri di valutazione per la scelta dei prodotti da analizzare
I prodotti che sono stati scelti per essere analizzati sono ORACLE 9i e Versant ODBMS per quanto
riguarda rispettivamente ORDBMS e ODBMS. Per quanto riguarda gli ORDBMS, la scelta è stata
dettata dalla necessità di evidenziare il maggior numero di estensioni possibili, e il database della
ORACLE si presta maggiormente a questo scopo in quanto tra tutti è quello che presenta il maggior
numero di nuovi tipi di dati ed estensioni OR utilizzabili. Per quello che riguarda gli ODBMS
invece, considerando anche la scarsa maturità della tecnologia si è cercato di unire le potenzialità
del database VERSANT alla facilità di trovare supporti bibliografici.
33
Capitolo 4 Oracle 9i (ORDBMS)
4.1 Breve storia del prodotto
Oracle nasce come Relational database fino a diventare Object-Relational con l’ultima versione che
stiamo considerando.
Ripercorrendo la storia del DBMS si possono evidenziare i seguenti step:
1988: Oracle Server V.6
Gestione automatica dei lock a livello di singola riga;
Introduzione del linguaggio PL/SQL, estensione procedurale del linguaggio SQL;
Maggiore scalabilità del sistema tramite il supporto di macchine multi-processore e macchine in
cluster (Parallel Server);
Introduzione di SQL*DBA;
Tecniche sofisticate di backup e recovery “a caldo” che massimizzano la disponibilità dei dati in
caso di crash del sistema;
Tool Oracle*CASE per il controllo completo di tutte le attività connesse allo sviluppo di
applicazioni (analisi, disegno dati, disegno dei moduli applicativi, generazione automatica di codice
PL/SQL).
1992: Oracle Server V.7
Introduzione di una nuova struttura di memoria condivisa dalle applicazioni detta Shared Pool
(SGA);
Accesso trasparente a dati distribuiti sia in lettura che in modifica (Two-Phase Commit);
Potenziamento della security con l’introduzione dei concetti di Ruolo e Privilegio di Sistema;
Inserimento statement dichiarativi (Constraints) e scrittura di codice PL/SQL integrato alle tabelle
(Triggers);
PL/SQL utilizzato per creare stored procedures memorizzate nel database;
Ottimizzazione delle query (tecnica Cost Based);
manutenzione ed accesso in modo efficiente e flessibile a dati non strutturati (testi, video,
immagini).
1997: Oracle8 Server V.8.0
Potenziamento delle funzionalità a supporto degli ambienti Data Warehouse e più in generale
VLDB(Very Large Database);
Introduzione dell’architettura NCA (Network Computing Architecture).
1999: Oracle8i Server V.8.1
Ulteriore potenziamento delle funzionalità rivolte ai VLDB;
Integrazione di una Java Virtual Machine (JVM) nel kernel di sistema;
Affiancamento del linguaggio Java al PL/SQL per lo sviluppo di applicazioni web-based.
34
2001: Oracle9i Server
Unico Parser per il motore SQL e PL/SQL;
Integrazione del modulo di Runtime per SQL e PL/SQL;
Nuovi Date/Time Data Types;
Migliore integrazione e maggiore flessibilità per i LOBs;
Migliorato il supporto per XML;
PL/SQL Object Inheritance;
Nuovi funzionalità SQL;
SGA dinamica – modifiche senza shutdown.
4.2 Architettura
L’architettura di Oracle9i è mostrata in Fig. 4-1.
Fig. 4-1. Architettura
L’architettura interna di Oracle9i è thread-based. I threads sono oggetti all’interno di un processo
che eseguono le istruzioni del programma. I threads permettono operazioni concorrenti cosicché un
processo può eseguire diverse parti di programma simultaneamente su processori diversi.
Un’architettura thread-based offre i seguenti vantaggi:
• Faster context switching
• Routine di allocazione della memoria globale più semplice
• Gestione più veloce delle connessioni
35
•
Decremento di carico computazionale
Internamente, il codice che implementa il modello dei thread è compatto e separato dal corpo
principale di codice Oracle. Le eccezioni e le routine allocano e deallocano risorse. Esse
aggiungono robustezza senza perdite di prestazioni.
Il database Oracle9i non è un tipico processo Windows; un’istanza Oracle (i threads e le strutture
dati) è un servizio di Windows: un processo in background registrato all’interno del sistema
operativo. Il servizio viene avviato dal sistema operativo e non richiede interfacce utente per partire.
Quando si avviano istante multiple di Oracle su Windows, ognuna avvia il suo servizio con threads
multipli.
Shared Pool
- Library Cache
Contiene i metodi di esecuzione e la struttura degli alberi di parsing per gli statement SQL
da svolgere sul database
- Dictionary Cache
Contiene dati dell’Oracle data dictionary
Data Buffer Cache
Contiene i dati recuperati dal database via SQL Statement.
Si basa su due strutture:
• dirty list
• recently used (LRU) list
Quando un processo utente necessita di un buffer di memoria, il processo server che gestisce il Data
Buffer Cache scansiona la LRU list per trovare dei buffer liberi.
La dimensione del Data Buffer Cache è definita dai parametri DB_BLOCK_SIZE*
DB_BLOCK_BUFFERS nel file init<SID>.ora.
4.3 Tipi di dati
Il Server diventa Object-relational; è così possibile il supporto alla definizione di dati complessi
(record, array) e non strutturati (BLOBs - BinaryObjects) (Fig. 4-4).
Fig. 4-4. Tipi di dati di Oracle9i
36
Oracle9i Server supporta la definizione di Object Views, speciali oggetti, implementati anche come
tools, capaci di presentare dati presenti su tabelle relazionali “pure” come oggetti definiti tramite il
comando CREATE TYPE.
Questi tools(mapping tools) permettono ai programmatori di associare delle righe di una tabella
relazionale ad istanze di una classe (es. oggetti). Inoltre permettono di vedere dinamicamente delle
righe come oggetti puri, rimpiazzando le chiavi esterne con dei puntatori reali. Rappresentano
perciò un utile strumento da usare con database relazionali già esistenti e nuove applicazioni objectoriented.
Per quanto riguarda i dati predefiniti:
CHAR
NCHAR
NVARCHAR2
VARCHAR2
LONG
RAW
LONG RAW
NUMBER
DATE
CLOB: Character Large Object
BLOB: Binary Large Object
BFILE: External Files
– Supportano fino a 4GB di informazioni per singolo dato
– Accesso indicizzato ai dati
– Accesso in lettura a dati memorizzati in file di Sistema Operativo
– Interfaccia programmatica: C/C++ o PL/SQL
VARRAY
TABLE
REF
4.4 Funzionalità SQL99 implementate
CREATE TYPE
Il costrutto CREATE TYPE permette la creazione di 3 tipi di dati:
- Object types: astrazioni di entità reali le quali possono essere definite anche in maniera incompleta
- Table types: set non ordinato di elementi di dati, tutti dello stesso tipo, costituito da una sola
colonna ; il tipo Table può essere utilizzato come tipo di dati di una colonna di una tabella oppure
come attributo di un object type o ancora come tipo di parametri o ritorno di funzioni
- Array types: set ordinato di elementi di dati, tutti dello stesso tipo, costituito da una sola colonna.
ROW TYPES E COLUMN TYPES
Le row types sono tipi utilizzati come tipi oggetto, ovvero tipo di ogni istanza di tabella.
Le column types sono tipi utilizzati come tipi di attributo; è così possibile dichiarare tabelle con
attributi di tipo complesso o definito dall’utente.
37
METODI E COSTRUTTORI
Per metodi si intendono funzioni o procedure; l’implementazione dei metodi avviene all’interno di
un unico object body per tipo; i metodi possono accettare/ritornare parametri attraverso il comando
IN, OUT oppure IN OUT; l’ordinamento può essere gestito tramite la clausola order by, mentre la
clausola order davanti ad una funzione membro confronta due oggetti del tipo corrente ritornando
un intero. Infine è possibile utilizzare l’opzione pragma al fine di dettagliare le capacità di un
metodo.
VISTE GERARCHICHE
È possibile creare una vista ed interrogarla.
ANY TYPE, ANY DATA
SYS.ANYTYPE: descrizione di tipo(qualunque SQL type), named o unnamed. ANYTYPE è
transiente: non è memorizzato nel database.
SYS.ANYDATA: contiene un’istanza di un qualunque tipo, più la sua descrizione di tipo. E’
self-describing. Un ANYDATA può essere memorizzato nel database.
SYS.ANYDATASET: è un insieme self-describing di dati di qualunque tipo: contiene la
descrizione del tipo più un insieme di istanze di quel tipo.
Si può creare o convertire(CAST) dati da qualunque tipo SQL ad ANYDATA e viceversa.
4.5 Creazione dello schema
Per la creazione dello schema in Oracle 9i si fa uso di Oracle Enterprise Management console.
Questo strumento permette di eseguire tutte le operazioni necessarie per creare lo schema del
database tramite un wizard. Gli elementi che possono essere inseriti vanno da quelli relazionali
(tabelle, viste, trigger, ecc.), a quelli ad oggetti (object type, tipi di array, tipi di tabella, ecc.) (Fig.
4-5).
Fig. 4-5. Elementi inseribili nello schema
38
Nel wizard è presente anche la possibilità di visualizzare le istruzioni SQL associate all’operazione
che si sta compiendo.
Esempio: Creazione dell’Object Type “Utente”:
CREATE TYPE UTENTE_TYPE AS OBJECT
(NOME VARCHAR2(20),
COGNOME VARCHAR2(20),
INDIRIZZO VARCHAR2(20),
TELEFONO VARCHAR2(15),
FAX VARCHAR2(15),
EMAIL VARCHAR2(15),
USERNAME VARCHAR2(15),
PASSWORD VARCHAR2(20),
FL_AMM VARCHAR2(1),
CONT ARRAY_CONTATTI )
Dall’esempio precedente si nota che ad Utente è associato un array di contatti.
Esempio: Creazione del Tipo di Array “Array di Contatti”:
CREATE TYPE ARRAY_CONTATTI AS VARRAY(1) OF CONTATTO
Nell’esempio precedente è necessaria la creazione dell’Object Type “Contatto”.
A questo punto è necessaria la creazione delle tabelle.
Esempio: Creazione della tabella “Utente”:
CREATE TABLE UTENTE OF UTENTE_TYPE
4.6 Tools dedicati
A seguito dell’installazione di Oracle e a seconda della versione installata, saranno disponibili
alcuni tools; questi applicativi possono essere lanciati separatamente ma per una integrazione dei
servizi è stato sviluppata una console di gestione, la Oracle enterprise manager console.
Oracle enterprise manager console
Oracle Enterprise Manager è una soluzione integrata per amministrare e monitorare il DBMS.
Enterprise Manager è basato su di un’architettura a pila composta da tre livelli (Fig. 4-5):
•
•
•
Console, applicazioni integrate e Management Packs
Management Server(s) e database repository
Intelligent Agents
39
Fig. 4-6. Struttura di Oracle Enterprise Manager
Console centralizzata
la responsabilità primaria della console è quella di presentare una user interface agli amministratori
per tutti i loro compiti di gestione.
In relazione a quanto installato sul sistema in uso, il primo livello dell’architettura potrebbe
consistere dei seguenti componenti:
Console: dalla versione 9.0 in poi le funzionalità di Oracle DBA Studio sono state completamente
integrate nella console.
Applicazioni integrate:
Oracle Forms Server Manager,
Oracle Policy Manager,
Oracle Directory Manager,
Oracle Net Manager,
Oracle Spatial Index Advisor,
Oracle Data Guard Manager,
Oracle LogMiner Viewer,
Oracle Enterprise Security Manager,
Oracle Text Manager.
Applicazioni dai Managements Packs:
Oracle Diagnostic Pack:
Oracle Performance Manager,
Oracle Capacity Planner,
Oracle TopSessions,
Oracle Trace.
Oracle Tuning Pack:
Oracle Expert,
Oracle Index Tuning Wizard,
40
Oracle SQL Analyze,
Oracle Tablespace Map,
Reorg Wizard,
Outline Editor,
Outline Management.
Oracle Change Management Pack:
Oracle Change Manager.
Oracle Standard Management Pack:
Oracle Performance Manager,
Oracle Index Tuning Wizard,
Oracle Create Baseline,
Oracle Compare Database Objects,
Oracle Advanced Database and Node Events.
Oracle Management Pack for Oracle Applications:
Oracle Performance Manager,
Oracle Capacity Planner,
Concurrent Processing Tuning Assistant,
Oracle Applications Advanced Events.
Oracle Management Pack for SAP R/3:
Oracle Performance Manager,
Oracle Capacity Planner,
Oracle Advanced Events.
Oracle enterprise manager console è disegnata per ridurre la complessità della gestione del DB
server Oracle, come anche i componenti distribuiti, il software e l’hardware che supportano il DB.
Siccome il primo livello dell’architettura dipende dal Management server(secondo livello), i clients
sono in grado di funzionare senza overhead e carico computazionale dei servizi di management del
sistema.
Oracle Management server centrale, scalabile e affidabile
Il secondo componente dell’architettura del tool in esame, il management server, è il framework
engine. Il Management server mantiene una intelligenza centralizzata e un controllo distribuito tra i
clients e i nodi del server. È responsabile per tutte le applicazioni back-end e i servizi critici(eventi
di sitema, reporting, job system...) .
Questo processo tra i clients e gli agenti intelligenti intercetta richieste dal primo livello, memorizza
le informazioni in una db repository e distribuisce i compiti agli agenti intelligenti del terzo livello
che li eseguono.
Agenti intelligenti autonomi:
il terzo ed ultimo livello consiste di managed targets e agenti intelligenti. I managed targets, che
possono includere nodi, database, web server, application server ed altro, chiedono agli agenti di
eseguire compiti(tasks) presi dal manager server. Una volta assegnati i tasks, agenti autonomi
eseguiranno il lavoro programmato con noncuranza dello stato dei managed targets, dei
management server o dei clients. Esempi di tasks significativi sono l’esecuzione di script SQL, il
monitoraggio dello spazio disponibile in una tablespace, la creazione di backup settimanali, il
monitoraggio in real-time del rate I/O del db o il monitoraggio della disponibilità dell’application
server.
41
Enterprise manager console può essere avviata in modalità standalone o con connessione verso il
management server. Quando si accede al tool in modalità standalone, la console non si connette al
livello intermedio e cioè al management server.
Siccome non richiede il management server o gli agenti intelligenti, la console in modalità
standalone permette al singolo amministratore di creare sempici schemi di database, istanze e altri
compiti connettendosi direttamente al database di interesse(database target).
Questa modalità è stata utilizzata per lo sviluppo dell’applicazione d’esempio che ha richiesto uno
schema di database molto semplice.
42
Capitolo 5 Versant (OODBMS)
5.1 Breve storia del prodotto
Gli ODBMS apparvero sul mercato a partire dal 1980. L’obiettivo era quello di avere un database
che fosse designato ed ottimizzato per memorizzare e manipolare oggetti.
Inizialmente, invece di focalizzarsi sul modello dei dati (basato su un insieme determinato di tipi), il
database si focalizzava su un modello ad oggetti definito con linguaggio O-O.
Nel 1988, Versant ha iniziato a lavorare ad una architettura object-oriented che sia scalabile e
distribuita e ha brevettato un algoritmo di caching. Il primo prodotto è stato il Versant Object
Database Management System (ODBMS), che è stato visto come il primo database ad oggetti
enterprise-scalabile. Autorevoli servizi di telecomunicazioni e finanza e compagnie di difesa e
trasporto dipendevano da Versant per risolvere alcuni dei problemi delle applicazioni di data
management. Applicazioni come la scoperta di frodi, analisi di rischio, management della
produzione, collezione ed analisi di dati in real-time hanno beneficiato dall’unica architettura
object-oriented di Versant.
5.2 Caratteristiche
L’Object Data Management Group (ODBMG) ha definito dei linguaggi standard per C++,
Smalltalk e Java per i database ad oggetti. Lo standard definisce:
• Come un modello ad oggetti è definito ed immagazzinato in un database (Object Definition
Language). Lo standard mette a disposizione un ODL separato, ma generalmente C++,
Smalltalk o Java sono usati come linguaggi di definizione.
• Come l’applicazione interagisce con l’Object Manager per manipolare gli oggetti (Object
Manipulation Language). Questo definisce il linguaggio interfaccia per C++, Smalltalk e
Java.
• Come l’applicazione può fare una query sul database (Object Query Language). Ogni
linguaggio interfaccia permette di esprimere ed eseguire query OQL. Solo i database ad
oggetti con object-aware servers di passare e far eseguire la query al server. Gli altri usano il
client per eseguire la query, trasferendo tutti gli oggetti dal database per poi verificare se c’è
un’eguaglianza.
Versant è stato progettato come un vero Database per oggetti, mettendo anche a disposizione
operazioni su gruppi di oggetti. Consente così di minimizzare il carico sulla di rete e massimizzare
la concorrenza grazie alla possibilità di gestire il Locking su singoli oggetti o gruppi. Inoltre, il
supporto a transazioni estese, grazie alla possibilità di politiche di Optimistic Locking ed Event
Management, permette prestazioni vicine a quelle di Database Memory-resident.
L'architettura del Server Versant è interamente Multi-thread. Per applicazioni in grado di sfruttare
Thread multipli, Versant mette a disposizione delle API Thread-safe. Questa possibilità mette in
grado l'utente di sfruttare a pieno le potenzialità di sistemi multi-processore, consentendo di
raggiungere prestazioni estremamente elevate. Inoltre, Versant offre la possibilità di accessi
Multisession al Database, permettendo così ai Thread di creare transazioni multiple.
Versant è tipicamente utilizzato in un’architettura a 2-tier (client/server) o a 3-tier. Questo spiega il
supporto per thread multipli sia nel front-end di Versant (il client nel 2-tier, l’application server nel
3-tier), che nel back-and di Versant (il server).
43
Fig. 5-1. Architettura 2-tier di Versant
Fig. 5-2. Architettura 3-tier di Versant
A differenza degli altri prodotti, Versant utilizza l'identificazione logica degli oggetti. Il
mantenimento dell'integrità referenziale del Database, la migrazione di oggetti attraverso la rete, il
Clustering e la gestione dello spazio su disco avvengono automaticamente e in modo trasparente.
Versant può referenziare indifferentemente oggetti in memoria, in un Database locale o remoto,
attraverso
le
stesse
modalità
di
navigazione
tramite
puntatori.
La struttura Dual Cache dell'architettura Client/Server bilanciata di Versant, l'esecuzione delle
Query e la gestione degli eventi sul Server permettono di sfruttare al meglio l'infrastruttura
Hardware disponibile. Grazie all'integrazione con gli Application Server più affermati è possibile
scegliere l'architettura applicativa più adatta, senza vincoli e con la garanzia di una scalabilità totale.
44
Versant offre standard elevati di continuità di servizio per applicazioni Mission Critical. Full
Backup, gestione dello spazio su disco ed evoluzione dello schema vengono effettuati On-line, così
come tutte le operazioni di Routine di manutenzione del Database.
Versant offre un ricco panorama di soluzioni per il supporto allo sviluppo di applicazioni Objectoriented in C++, Smalltalk e Java. L'integrazione trasparente con questi linguaggi permette di
memorizzare l'Object Model dell'applicazione, direttamente nel Database, senza le conversioni
necessarie
con
un
Database
relazionale.
La disponibilità di strategie di condivisione trasparente di oggetti tra linguaggi diversi, permette di
utilizzare il linguaggio appropriato a ciascuna situazione di sviluppo. Inoltre sono disponibili
integrazioni
con
i
più
diffusi
strumenti
di
sviluppo
sul
mercato.
Versant supporta lo sviluppo di applicazioni C++ su Database il cui schema viene derivato
direttamente dai file Header del C++. Non necessitando di alcun preprocessore o compilatore
speciale, Versant, grazie anche alla integrazione con i più comuni Tool di sviluppo, offre agli
sviluppatori un alto livello di produttività con una bassa curva di apprendimento.
Versant ha abbracciato Java come linguaggio universale per lo sviluppo di applicazioni.
In Fig.5-3 è mostrata l’architettura di Versant.
Fig. 5-3. Architettura di Versant
5.3 Installazione
Configurazione
Completata l’installazione sono state aggiunte delle informazioni nel registro: è stata aggiunta una
riga alla fine del file etc/services, e sono state aggiornate delle variabili d’ambiente tra le quali
CLASSPATH e PATH.
Una tipica struttura ad albero di Versant è mostrata in Fig.5-4.
45
Fig. 5-4. Struttura installazione di Versant
L’installazione di Versant Developer Suite permette di avere i componenti mostrati in Tab. 5-1.
46
Tab.5-1.
Il Versant ODBMS mette a disposizione le funzionalità generali di un database con una elevata
scalabilità per la gestione delle transazioni dual-cache per sistemi distribuiti multi utente.
La Java Interface di Versant (JVI) permette una completa persistenza trasparente per oggetti di
business senza cambiare modello delle classi java e permettere di memorizzare e condividere gli
oggetti tra applicazioni diverse senza effettuare una mappatura.
Come la Java Interface, l’interfaccia C++ di Versant permette una completa persistenza per oggetti
C++, dove il modello dell’applicazione C++ è l’esatta rappresentazione del modello dati
memorizzato in un database e condiviso tra applicazioni diverse. Un oggetto può essere recuperato,
tramite la deferenziazione del suo puntatore.
Il Toolkit XML di Versant mette a disposizione delle estensioni che permettono di rappresentare un
database ad oggetti di Versant in XML.
L’Asynchronous Replication di Versant (VAR) permette un aggiornamento differito da e verso
surgenti di dati multiple. Questo facilita il load balancing in sistemi multipli ed eterogenei con un
consistente aumento delle performance.
5.4 Tipi di dati
Tipi Object
Gli object sono utili se si vuole organizzare una grande quantità di codice e gestire dei tipi di dati
complessi. Il termine object ha numerosi significati:
Object: un “object” database è un componente software che può incapsulare dati e referenziare altri
object.
Istance Object: è un database object che può mantenere dati. In un database Versant, un object ha
una classe che definisce quali tipi di dati sono associati all’object.
47
Class Object: quando si crea una classe, Versant crea uno speciale tipo di object chiamato “class
object” o “schema object” che memorizza la definizione dei tuoi tipi di dati in un database. Si
possono definire classi che contengono ogni genere di dato, includendo values, sounds, documents
o referenziazioni ad altri object.
Versioned Object: per tracciare l’evoluzione degli stati di una istance object, Versant permette di
convertire una istance object in “versioned object”, questo perché ci possono essere numerose
versioni di una istance object.
Transient Object: esiste solo mentre il programma che lo ha creato è in fase di running.
Persistent Object: è un object che può essere memorizzato in un database Versant.
Stand-alone Object: viene creato con l’operatore new di C++, con l’operatore o la funzione new di
C++/Versant o un object definito come variabile locale o globale.
Embedded Object: è un object che è attributo di un altro object.
Smart Object: seleziona automaticamente la versione corretta di un object basandosi su una
configurazione pre-selezionata.
Elementi di Object
Nonostante gli object hanno una struttura singola, la loro implementazione coinvolge differenti
elementi discreti:
• Attributi: le parti di un object che memorizzano dati e associazioni con altri oggetti. Un
attributo è persistente quando l’object che lo contiene è persistente. Gli attributi vengono
definiti in una classe. Dopo che una classe è stata compilata, la definizione degli attributi è
caricata in un database e memorizzata in object. I dati attuali sono memorizzati un una
istanza di object.
• Metodi: le parti di un object che contengono parti di codice eseguibile. I metodi sono
definiti e implementati in una normale classe.
Caratteristiche di Persistent Object
Object Identity: Versant assegna ad ogni persistent object un identificatore unico chiamato logical
object identifier (loid). Un loid è formato da due parti: il database identifier e l’object identifier.
Il database identifier è l’identificatore per la creazione del database che è univoco in un
sistema composto da più database. L’identificatore è creato da Versant quando il database viene
creato.
L’object identifier è l’identificatore creato da Versant quando l’oggetto è creato. L’object identifier
è unico all’intero di un database.
Object Migration: la capacità di migrare gli object rende i database distribuiti più pratici. Dopo che
gli object sono stati creati, ci può essere la necessità di migrarli dove possono essere maggiormente
usati, riducendo sia il traffico sulla rete che lo spazio occupato in memoria. Object e database
identifier non cambiano dopo che un object è migrato o è cambiato. Anche quando un database o un
object sono stati cancellati, gli identificatori non vengono riusati. Questo comporta non dover
riscrivere il codice quando un oggetto migra.
Ogni oggetto persistente deve avere una class object che contiene la definizione della classe.
Quando un oggetto migra in un nuovo database, se non è stato definito nel database target, deve
migrare anche una copia della sua class object.
48
Dynamic Binding: quando viene definita una classe che specializza una classe base, ci può essere
la necessità di ridefinire dei metodi. I metodi ereditati possono essere ridefiniti in una sotto-classe.
Polymorphism: è possibile fare l’overload di un metodo, definendo varie copie che differiscono dal
numero e dal tipo degli argomenti.
Situation Modeling: un vantaggio nell’uso del modello ad oggetti è la sua abilità a modellare le
situazioni in una maniera realistica che può essere compresa da tutti.
Schema Modification: dopo aver completato una applicazione ci può essere la necessità di
estendere o modificare le sue classi per soddisfare nuovi task. L’insieme della definizione degli
object associati ad un database è chiamato “schema” del database. In qualsiasi momento è possibile
aggiungere o modificare lo schema di un database.
Predefined Types
Versant dispone di alcuni tipi elementari che possono essere usati con embedded, inheritance e
association relationship. I seguenti tipi sono disponibili in tutte le interfacce:
• Vstr: ha un overhead piccolo, ed una lunghezza di memorizzazione variabile per uno o più
valori elementari.
• Link: contiene la referenziazione ad altri object.
• Link vstr: ha una lunghezza di memorizzazione variabile per uno o più referenziazioni ad
altri object.
C/Versant prevede anche il seguente tipo:
• List: è un insieme ordinato di valori con lunghezza di memorizzazione variabile.
C++/Versant prevede anche i seguenti tipi:
• Bi-link: memorizza una referenziazione bidirezionale.
• Bi-link vstr: ha una lunghezza di memorizzazione variabile per uno o più referenziazioni
direzionali.
• Array: è una collezione ordinata di elementi accessibile da un indice di tipo Integer.
• Set: è una collezione non ordinata di elementi univoci.
• Dictionary: è una collezione che mappa delle chiavi con dei valori.
• List: ha una lunghezza di memorizzazione variabile con ordinamento
• Date e Time: tipi attributo di tipo date e time.
L’interfaccia C++/Versant permette di creare anche i seguenti tipi:
• Paramaterized: garantiscono un’unica definizione per quelle classi che differiscono solo dal
tipo di dato del loro contenuto. E’ utile per classi che hanno la stessa funzione ma hanno dei
dati di tipo diverso.
• Run-time: classi che sono definite a run-time.
• Smart: selezionano automaticamente la corretta versione di un object basandosi su una
configurazione pre-selezionata.
Versant permette anche di usare third class libraries.
Stato degli oggetti
Quando si crea o si accede ad un database object, Versant mantiene informazioni sul suo stato
corrente.
Object transient, persistent status: quando si crea un object verifica se è transient o persistent. A
livello di scope di una transazione i due tipi di object sono trattati nella stessa maniera, ma dopo un
comando commit, solo gli oggetti persistenti vengono memorizzati nel database.
49
Object lock status: il lock permette un accesso garantito agli object. Per esempio un write lock
garantisce che tu sei il solo user di un object, che è importante se vuoi aggiornare l’object.
Object dirty status: quando un oggetto viene modificato, può essere marcato come “dirty”; questo
significa che sarà aggiornato al successivo commit. Questo garantisce un miglioramento delle
prestazioni in quanto dopo un commit, Versant non dovrà comparare il contenuto di ciascun object
con il suo contenuto originale, per determinare quali object devono essere aggiornati.
Object versioned status: è possibile tenere traccia dell’evoluzione degli stati di un object nel
tempo, convertendo non-versioned object in versioned object.
Quando un non-versioned object viene aggiornato, i suoi vecchi dati vengono sovra scritti. Quando
un versioned object viene aggiornato, il vecchio object è preservato e il nuovo object è creato con i
nuovi dati. Il nuovo object è chiamato “child”, mentre il vecchio object è chiamato “parent”.
Versioned object che hanno lo stesso parent sono chiamati “siblings”.
Ogni versione di un object ha un identificatore unico, un numero ed uno stato della versione, che
può essere transient, working o released.
Object configuration
E’ possibile raggruppare specifiche versioni di differenti object in “configuration”, e
automaticamente selezionare la versione corretta di un object, utilizzando un “smart object”.
Object checkout status: è possibile fare check out su un object da un group database accessibile da
vari utenti, verso un personal database accessibile da un solo utente. Quando si fa check out su un
object, viene creata una copia nel personal database e viene messo un lock sull’object originale.
Questo permette di lavorare sull’object per un periodo illimitato di tempo senza tener conto del
traffico di rete.
Object pin status: per garantire una gestione efficiente della memoria, Versant mette in una object
cache gli object a cui si accede durante una transazione.
Relazione tra object
Object embedded relationship: una “embedded relationship” è creata quando un object viene
usato come attributo di un altro object. Può anche essere chiamata “contains-a” o “containment
relationship”. Usare embedded object garantisce un aumento delle performance, perché con un solo
passo si accede ad una aggregazione di object, e il lock viene fatto su una sola entità.
Object inheritance relationship: quando si definiscono degli object è possibile definire una
struttura gerarchica. In questa gerarchia gli object discendenti ereditano attributi e metodi.
L’ereditarietà è un modo efficiente di descrivere una situazione: una classe di base descrive le
caratteristiche comuni alle classi derivate, mentre ciascuna classe derivata avrà delle caratteristiche
proprie. Dato che le classi derivate, ereditano sia attributi che metodi, la definizione del codice
diventa riusabile, estendibile e personalizzabile.
Ci sono due tipi di ereditarietà: singola e multipla.
L’ereditarietà singola descrive un object legato a più ancestor in una struttura a stack.
L’ereditarietà multipla descrive un object legato a più ancestor in una struttura ad albero (tree).
Object association relationship: una caratteristica importante del modello ad oggetti è l’abilità di
associare object logicamente legati, ma di tipo differente.
L’associazione tra oggetti è simile all’uso del puntatore tra due object, supponendo che ad entrambe
sia stato associato un indirizzo virtuale di memoria.
50
Per creare dei puntatori persistenti al database, C++/Versant usa i “link”. I link vengono anche
chiamati “smart pointer”, dato che rimangono validi anche se l’object viene spostato da un database
ad un altro.
L’uso dei link permette miglioramento delle performance: infatti è più rapido trovare un object in
un database usando un link rispetto una query.
5.5 Creazione dello schema
L’Enhancer è un tool che post processa classi java modificandole dopo essere state compilate.
L’Enhancer accetta in ingresso file di tipo .class e produce una nuova classe in uscita. Il tool
produce cambiamenti alle classi secondo le specifiche scritte in un file di configurazione.
I cambiamenti delle classi includono:
• Codice generato per definire lo schema del database ad oggetti;
• Codice generato per leggere e scrivere gli oggetti persistenti su e da il database;
• Codice modificato per aggiungere proprietà aggiuntive nell’accesso ai campi di un oggetto
persistente.
Esecuzione dell’Enhancer
L’Enhancer può essere invocato in due differenti modi:
• Come standalone utility
• Come Java class loader
Nell’applicazione d’esempio si è utilizzato il primo modo, per cui si farà riferimento solamente a
quello.
Standalone Enhancer utility
Questa applicazione, quando è eseguita, esegue i seguenti passi:
• Legge il file di configurazione sulla riga di comando;
• Legge ogni file .class (o collezione di file in una directory) specificato sulla riga di
comando;
• Aggiunge codice ad ogni .class usando le informazioni contenute nel file di configurazione.
L’invocazione del tool avviene tramite riga di comando:
java com.versant.Enhance –in <cartellaSorg> -out <cartellaDest>
-config <configFile>
Il file di configurazione presenta una struttura del tipo:
<categoria di persistenza> <classe java>
Alcune categorie di persistenza sono:
• “c”, Persistent Capable: gli oggetti della classe diventano persistenti esplicitamente (tramite
invocazione di appositi metodi);
• “p”, Persistent Always: gli oggetti della classe diventano persistenti quando l’oggetto viene
creato;
• “n”, Not Persistent Aware: l’Enhancer non modifica queste classi.
Esempio creazione schema nell’applicazione d’esempio:
Il file di configurazione per l’applicazione d’esempio ha la seguente struttura:
51
c progetto_tesi.Appuntamento
c progetto_tesi.Contatti
c progetto_tesi.Data
c progetto_tesi.Utente
Il risultato prodotto è la classe modificata (o collezioni di classi) più un ‘altra classe con nome
esteso rispetto alla principale consistente in nomeClasse_Pickler_Vj.class.
Per esempio per quanto riguarda la classe appuntamento il risultato prodotto sarà:
Appuntamento.class
Appuntamento_Picker_Vj.class
La seguente Fig.5-5 mostra il risultato della chiamata del tool.
Fig. 5-5. Esecuzione dell’Enhancer
5.6 Tools dedicati
Uno degli elementi da valutare nella scelta di un database è la possibilità di avere a disposizione dal
produttore un insieme di tools. Di particolare importanza sono le utility di backup e recovery, quelli
che riguardano l’amministrazione del database e l’analisi delle performance.
Nell’area del backup e del recovery, un produttore di database dovrebbe provvedere a delle capacità
automatiche di backup. Dato che i principali ODBMS vengono usati per applicazioni distribuite è
importante l’esecuzione di backup distribuiti attraverso database multipli. Un'altra funzione
importante è l’uso di un roll-forward recovery log, il quale tiene traccia di tutte le transazioni fatte
dall’ultimo backup.
Tools dedicati all’amministrazione del database non devono essere in grado di supportare una
interfaccia grafica (GUI), ma anche la possibilità di funzionare tramite linea di comando, con la
possibilità di essere incorporati all’interno di scrip.
Per un progetto in cui vengano utilizzate tecniche object-oriented, un ODBMS (Object Data Base
Management System) è il miglior posto per mantenere oggetti persistenti. Le attuali tecnologie e gli
strumenti disponibili sul mercato permettono di rimanere in un ambito strettamente object-oriented
in ogni fase di progetto e, allo stesso tempo, i metodi di analisi, progettazione e sviluppo hanno
completato una fase di maturazione soddisfacente con "best practice" ben definite. Le tecniche di
produzione del software hanno dovuto subire una evoluzione, essendosi ridotti vertiginosamente i
tempi di rilascio accettati dal mercato dell’e-business, e questo ha favorito la definizione di metodi
"leggeri" che consentono cicli di sviluppo abbreviati. Il motivo più frequente è una progettazione
che non tiene adeguatamente in conto le criticità dei sistemi distribuiti, in particolare la gestione
delle transazioni e della persistenza degli oggetti. Il punto fondamentale e critico dello sviluppo è
mantenere il rispetto del paradigma object-oriented in tutte le fasi di realizzazione del sistema.
52
L’impiego di database relazionali per dare persistenza agli oggetti è la più comune fonte di
problemi nelle applicazioni a oggetti e a componenti. Ma è anche la più trascurata, malgrado sul
mercato esistano soluzioni mature ed estremamente efficienti e scalabili. Laddove le tecnologie a
oggetti vengono utilizzate con aspettative di successo, ormai più che giustificate, l’impiego di un
ODBMS per la persistenza degli oggetti è la scelta naturale.
I vantaggi che derivano dall’impiego di un ODBMS per la persistenza di oggetti sono molto
evidenti in termini di minori costi e tempi di sviluppo e di migliori prestazioni e scalabilità.
L’utilizzo di un database a oggetti permette di superare i limiti di scalabilità delle tecnologie
tradizionali, di quelle relazionali in particolare. In un pieno rispetto del paradigma object-oriented, il
modello delle classi e dei componenti è lo schema del database e non avviene nessuna conversione
e semplificazione del modello nella gestione della persistenza. La complessità del modello objectoriented viene rispettata e la navigazione tra oggetti offre prestazioni più elevate di alcuni ordini di
grandezza rispetto all’equivalente relazionale, oltre a forti risparmi nei costi di sviluppo, grazie
all’assenza di qualsiasi strato di mapping. Un’entità reale non è "una singola riga di una singola
tabella di un singolo database relazionale".
La tecnologia degli ODBMS si può definire ormai decisamente matura. Nel corso degli ultimi anni
l’affermazione delle tecnologie a oggetti è diventata una realtà, grazie anche a una evoluzione
generale di tutte le tecnologie informatiche, che sicuramente hanno dato un contributo. Le
tecnologie a oggetti in generale, e dei database in particolare, hanno avuto difficoltà di affermazione
nel passato, anche a causa di alcune immaturità di altre tecnologie di contorno, come i protocolli di
comunicazione e senz’altro l’hardware. Si tratta tuttavia di un passato ormai lontano. Il futuro si
delinea chiaramente con una adozione delle tecnologie a oggetti che diventa sempre più massiccia.
Del resto le esigenze dei mercati più competitivi, come quello delle telecomunicazioni o quello
finanziario, non lasciano spazio a incertezze. Le necessità di prestazioni, scalabilità, flessibilità,
tempi di realizzazione brevi e costi di possesso contenuti, accanto a una crescente complessità dei
business da servire, non possono più essere soddisfatte con le tecnologie tradizionali. Ma, mentre
nel settore degli strumenti di sviluppo e degli application server l’evoluzione a oggetti è ormai
avvenuta e si sta completando, nel settore dei database c’è una maggiore inerzia, che è dovuta al
notevole potere di mercato dei vendor dei DBMS relazionali. In questo scenario le prospettive per
una sempre più ampia adozione degli ODBMS sono decisamente favorevoli. Una spinta decisa da
parte delle necessità di mercato può accelerare il processo meglio di qualsiasi altra "naturale"
evoluzione tecnologica. Fortunatamente, la risposta tecnologica è già pronta e disponibile.
A seguito dell’installazione di Versant, sono disponibili alcuni tools:
• Administration Console: per mezzo di una visualizzazione tramite tabella, vengono
mostrati tutti i database presenti sulla macchina. Per ogni database è possibile vedere la lista
delle classi, le transazioni attive, gli oggetti su cui si è effettuato un lock, la lista degli utenti
e le connessioni effettuate;
• Monitoring Console: permette di monitorare un database Versant attraverso un’interfaccia
grafica
• Object Inspector: mostra le classi e le loro istanze del database che è stato selezionato. La
struttura ad albero permette di visualizzare lo schema delle classi, con eventuali superclassi
o sottoclassi e la lista dei suoi attributi.
53
Capitolo 6 Applicazione d’esempio
6.1 Descrizione
L’applicazione sviluppata consiste in un’agenda multi agente per la gestione degli appuntamenti e
dei contatti.
6.2 Specifiche
Gli attori coinvolti nell’utilizzo dell’applicazione sono 2:
• Amministratore
• Agente
Use Case
Fig. 6-1. Use Case Amministratore
L’amministratore, nell’ambito della gestione degli appuntamenti (propri e no) può:
• Visualizzare appuntamenti;
• Inserire appuntamenti;
• Modificare appuntamenti;
• Eliminare appuntamenti.
L’amministratore, nell’ambito della gestione dei contatti (propri e no) può:
• Visualizzare contatti;
• Inserire contatti;
• Modificare contatti;
• Eliminare contatti.
L’amministratore, nell’ambito della gestione degli agenti può:
• Visualizzare agenti;
• Inserire agenti;
• Modificare agenti;
• Eliminare agenti.
54
Fig. 6-2. Use Case Agente
L’agente, nell’ambito della gestione degli appuntamenti propri può:
• Visualizzare appuntamenti;
• Inserire appuntamenti;
• Modificare appuntamenti;
• Eliminare appuntamenti.
L’agente, nell’ambito della gestione dei contatti propri può:
• Visualizzare contatti;
• Inserire contatti;
• Modificare contatti;
• Eliminare contatti.
Class diagram
Fig. 6-3. Class diagram
55
6.3 Linguaggio utilizzato
Per lo sviluppo dell’applicazione è stato utilizzato il linguaggio Java; più precisamente si è
utilizzato JBuilder X.
La scelta del linguaggio è stata dettata dal particolare tipo di base di dati utilizzata (Versant), la
quale, attraverso librerie dedicate, ha reso trasparente vari aspetti della programmazione tra cui la
gestione delle transazioni e l’interrogazione alla base di dati stessa.
6.4 Implementazione con ORDBMS
Per questo tipo di implementazione si è creata una classe denominata Database al fine di rendere più
veloce (in termini di numero di righe di codice scritte) l’interrogazione della base di dati.
Sviluppando con logica OR, i risultati di una query devono essere memorizzati in una struttura
(tipicamente un Resultset), per cui la classe database implementa i metodi che restituiscono le
strutture adatte per ogni tipo di comando SQL. Inoltre la classe Database si occupa anche di
instaurare la connessione con la base di dati.
Per ottenere il risultato di una query si passa una stringa (nella quale è contenuta la query stessa) al
metodo getResulset(String s) della classe Database creata; questo metodo ritorna un Resultset
utilizzabile per recuperare i dati.
Esempio “login”:
Questa query seleziona le righe della tabella TAB_UTE discriminando i campi Username e
Password; se viene trovata almeno una riga (esattamente una nel nostro caso) allora si testa un
campo del Resultset per differenziare l’amministratore dall’utente normale, altrimenti si evidenzia il
messaggio “INVALID USERNAME/PASSWORD”.
String q1 = "SELECT FL_AMM, USERNAME, PASSWORD FROM TAB_UTE WHERE USERNAME = '" +
jTextField1.getText() + "' AND PASSWORD = '" + jPasswordField1.getText() + "'";
Database db = new Database();
ResultSet rs = db.getResulset(q1);
try {
if(!rs.next() ){
jLabel4.setText("INVALID USERNAME/PASSWORD");
}
else{
jLabel4.setText("");
if(rs.getString("FL_AMM").compareTo("A") == 0){
//---AMMINISTRATORE--Frame frame11 = new Frame11(null, null, "A");
frame11.show();
}
else{
//---UTENTE--Frame frame11 = new Frame11(rs.getString("USERNAME"), rs.getString("PASSWORD"), "U");
frame11.show();
}
}
}
catch(SQLException ee){
System.out.println("Errore: " + ee);
}
Per la gestione delle funzionalità OR estese da SQL si riporta l’esempio dell’interrogazione di
tabelle con campi di tipo REF.
56
Esempio “inserimento appuntamento”:
L’inserimento dell’appuntamento segue l’inserimento in TAB_DATA della data associata
all’appuntamento; siccome in TAB_APP il campo DT_APP è di tipo REF, si è avuta la necessità di
selezionare la reference alla riga appena inserita per poterla utilizzare nella insert
dell’appuntamento; analogamente si è proceduto per la reference verso l’utente.
Il problema dell’inserimento di un appuntamento con data già presente in tabella è stato risolto
delegando all’applicazione il compito di visualizzare solamente le ore libere durante l’inserimento.
String str_rif_ute = " (SELECT REF(U) FROM TAB_UTE U WHERE U.USERNAME = '" + userTemp +
"' AND U.PASSWORD = '" + passTemp + "')";
String str_rif_dt_new = " (SELECT REF(D) FROM TAB_DATA D WHERE D.GIORNO = '" +
(String)jComboBox2.getSelectedItem() + "' AND D.MESE = '" + (String)jComboBox3.getSelectedItem() +
"' AND D.ANNO = '" + (String)jComboBox4.getSelectedItem() + "' AND D.ORA = '" +
(String)jComboBox1.getSelectedItem() + "')";
String str_insert_new_data =
"INSERT INTO TAB_DATA VALUES ('"
"'"
"'"
"'"
+
+
+
+
(String)jComboBox2.getSelectedItem()
(String)jComboBox3.getSelectedItem()
(String)jComboBox4.getSelectedItem()
(String)jComboBox1.getSelectedItem()
Database db4 = new Database();
int l = db4.esegui(str_insert_new_data);
if (l != 0){
System.out.println("insert e commit data nuova OK");
}
else{
System.out.println("insert data nuova KO");
return;
}
String str_insert_app_new =
" INSERT INTO TAB_APP VALUES ( '" + jTextField1.getText() + "' " +
", '" + jTextArea1.getText() + "' " +
", '" + jSlider1.getValue() + "' " +
", '" + jTextField2.getText() + "' " +
", " + str_rif_dt_new + " " +
", " + str_rif_ute + ")";
System.out.println(str_insert_app_new);
Database db5 = new Database();
int r = db5.esegui(str_insert_app_new);
if (r != 0){
System.out.println("insert app nuovo OK");
}
else{
System.out.println("insert app nuovo KO");
return;
}
+
+
+
+
"' ," +
"' ," +
"' ," +
"')";
57
6.5 Implementazione con OODBMS
Per questo tipo di implementazione le interrogazioni alla base di dati ad oggetti vengono effettuate
attraverso l’istanziazione di una classe proprietaria di Versant (VQLQuery). Dal nome della classe
si evince che il linguaggio di interrogazione non è OQL ma un tipo simile appositamente creato
dalla casa produttrice Versant.
La classe istanziata, a cui vengono passate la connessione e la stringa con la query di interesse,
ritorna un tipo Enumeration utilizzabile per recuperare gli oggetti appartenenti al risultato
dell’interrogazione.
Esempio “login”:
Questa query (VQLQuery) ritorna tutti gli oggetti di tipo Utente (nel nostro caso uno)
discriminando i campi Username e Password. Se l’Enumeration contiene l’oggetto cercato allora,
dopo un cast, si controlla l’attributo dell’oggetto che specifica il tipo d’utente così da riconoscere
l’amministratore dall’utente normale.
String str_conn = "select selfoid from progetto_tesi.Utente where username = '" +
(jTextField1.getText()) + "' AND password = '" + (jPasswordField1.getText()) + "'";
VQLQuery q1 = new VQLQuery (Application1.getSession(), str_conn );
Enumeration e1 = q1.execute();
if(!e1.hasMoreElements()) {
jLabel4 .setText("INVALID USERNAME/PASSWORD");
}
else {
while(e1.hasMoreElements()) {
Utente u = (Utente) e1.nextElement();
if(u.get_amm()) {
//---AMMINISTRATORE--jLabel4.setText("");
Frame frame11 = new Frame11(null, null, true);
frame11.show();
}
else {
//---UTENTE GENERICO--jLabel4.setText("");
Frame frame11 = new Frame11(u.getUsername(), u.getPassword(), false);
frame11.show();
}
}
}
Esempio “inserimento appuntamento”:
L’inserimento dell’appuntamento avviene dopo aver reso persistente la nuova data associata e
selezionato l’utente a cui l’appuntamento afferisce. L’inserimento della data nel database avviene
tramite il comando makePersistent(Object o).
Infine, l’appuntamento viene inserito passandogli l’oggetto data appena creato e l’oggetto utente
selezionato.
String str =
"select selfoid from progetto_tesi.Utente where username = '" +
userTemp + "' AND password = '" + passTemp + "'";
VQLQuery q2 = new VQLQuery(Application1.getSession(), str);
Enumeration e2 = q2.execute();
Utente u = (Utente) e2.nextElement();
Data dTemp = new Data( (String) jComboBox2.getSelectedItem(),
(String) jComboBox3.getSelectedItem(),
(String) jComboBox4.getSelectedItem(),
(String) jComboBox1.getSelectedItem());
Application1.getSession().makePersistent(dTemp);
Appuntamento aa = new Appuntamento(dTemp, jTextField1.getText(),
jTextArea1.getText(),
jSlider1.getValue(),
jTextField2.getText(), u);
58
Application1.getSession().makePersistent(aa);
}
Application1.getSession().commit();
6.6 Manuale utente
All’avvio dell’applicazione si apre il Frame del Login che permette l’autentificazione da parte
dell’utente.
Fig. 6-1. Frame Login
Una volta autentificato si apre il Frame principale, cioè quello dove vengono visualizzati gli
appuntamenti del giorno.
Fig. 6-2. Frame principale
59
Le fasce orarie occupate vengono visualizzate in rosso, mentre quelle libere rimangono in verde.
Nel caso in cui si effettua l’autentificazione e non si è amministratori, a differenza della figura 6-2 ,
verranno nascosti il bottone per la gestione degli utenti e la combo per la selezione dell’agente.
Da questo Frame si possono eseguire tutte le operazioni previste per l’applicazione.
Per esempio se si scegli di modificare un appuntamento si andrà a premere il bottone “Modifica”
sulla rispettiva fascia oraria. Il risultato sarà la visualizzazione del Frame relativo alla modifica
dell’appuntamento:
Fig. 6-3. Frame Modifica/Inserimento appuntamento
Un’altra operazione possibile (solo per amministratore) è la gestione degli utenti; premendo il
bottone relativo si apre il Frame:
Fig. 6-4. Frame Gestione utenti
60
Intuitivamente da questo Frame si possono aggiungere, modificare ed eliminare gli utenti.
Per aggiungere un nuovo utente, premendo il tasto corrispondente, si apre il Frame:
Fig. 6-5. Frame Modifica/Inserimento utente
La gestione dei contatti avviene in modo analogo a quella degli utenti, per cui si omette la relativa
descrizione.
61
Capitolo 7 Conclusioni
Il lavoro di confronto tra le due diverse tecnologie, ha portato a delle conclusioni a livello di
caratteristiche oltre a conclusioni derivate dallo sviluppo dell’applicazione. Riguardo alle
caratteristiche dei due tipi di tecnologie, le conclusioni si possono riassumere nei seguenti punti:
Supporto per i linguaggi di programmazione Object-Oriented
Oracle9i(OR): Per quanto riguarda questo prodotto, il supporto per i linguaggi OO è assicurato dal
fatto che per la connessione al db si utilizza un driver ODBC; a questo punto il passaggio dei dati
avviene prima dal db al driver, poi dal driver all’applicazione e viceversa.
Versant(OO): A differenza di Oracle, supporta a pieno C++ e Java attraverso delle librerie dedicate;
L’utilizzo di un driver non si rende necessario in quanto gli oggetti nello spazio del db sono anche
oggetti nello spazio dell’applicazione.
Semplicità d’uso(DBMS)
Oracle9i: Per quanto riguarda questo prodotto, la semplicità d’utilizzo è data dalla presenza di
numerosi tools che facilitano le operazioni di gestione di un DBMS tra le quali la creazione dello
schema, l’assegnamento dei ruoli e dei privilegi.
Versant: Per questo prodotto, la semplicità d’utilizzo non è paragonabile a quella di Oracle9i; le
operazioni di gestione sono in linea di massima più complicate da effettuare; un esempio è la
creazione dello schema(Object Schema) che per questo prodotto si realizza tramite l’invocazione di
un tool a riga di comando(Enhancer). Nonostante possa sembrare un problema rispetto a Oracle9i, i
benefici sulla semplicità d’uso si riscontrano a livello di programmazione dove risulta più
immediato usare direttamente oggetti senza forzarli(mapparli) in tabelle.
Semplicità di sviluppo(applicazione)
Oracle9i: Con un approccio alla programmazione Object-oriented, la semplicità di sviluppo e il
ciclo di vita dell’applicazione utilizzando questo prodotto vengono migliorati in quanto Oracle9i
supporta le estensioni al linguaggio SQL per la gestione degli oggetti.
Versant: Con questo prodotto la semplicità di sviluppo a livello di applicazione è assicurata dal fatto
che esiste una corrispondenza diretta tra l’applicazione OO e gli oggetti persistenti nel database;.
Estensibilità(tipi di dati)
Oracle9i: L’estensibilità nell’ambito di questo prodotto consiste nella possibilità di dichiarare nuovi
tipi di dati(ADT) oltre a quelli già supportati dal sistema; In ogni caso, vari vincoli devono essere
tenuti in considerazione creando sempre un compromesso tra estensibilità dei dati e funzionalità
dell’applicazione.
Versant: nell’ambito dell’utilizzo di questo prodotto, alle classi definite nell’applicazione
corrispondono oggetti persistenti nella base di dati; questa corrispondenza semplifica notevolmente
lo sviluppo in tutto il ciclo di vita dell’applicazione e migliora il suo mantenimento.
Complessità delle relazioni
La differenza della complessità delle relazioni si nota nel caso di relazioni non semplici(uno-auno);
Oracle9i: Per quello che riguarda questo prodotto, le relazioni a livello di diagramma E-R vengono
modellizzate nel db attraverso le funzionalità SQL aggiunte. Queste funzionalità permettono, tra le
altre cose, di creare relazioni attraverso l’utilizzo di attributi complessi.
Versant: Con questo prodotto, le relazioni sono facilitate in quanto l’utilizzo degli OID rende più
navigabili relazioni complesse.
62
Maturità della tecnologia
Oracle9i: La maturità della tecnologia di questo prodotto, siccome si presenta come estensione di
modelli precedentemente relazionali puri, risulta ormai consolidata con una reperibilità di materiale
consultativo.
Versant: La maturità della tecnologia di questo prodotto si presenta non soddisfacente in quanto
trovare riferimenti bibliografici non è così immediato; la scarsa maturità la si nota anche dal
limitato numero di tools presenti, fatto che sta ad indicare il cauto approccio verso questa
tecnologia.
Esperienza dei programmatori e universalità di SQL
Oracle9i: Per il prodotto in questione, l’esperienza dei programmatori si può considerare alta in
quanto è da molto tempo che l’approccio Object-Oriented viene utilizzato; inoltre la compatibilità
di SQL con tutti i prodotti di tipi OR assicura una familiarità con questo linguaggio.
Versant: In questo prodotto, il linguaggio di interrogazione è OQL(VQL nella versione
proprietaria); non esistendo una compatibilità piena tra OQL e SQL l’esperienza dei programmatori
viene ridimensionata azzerando praticamente la curva di apprendimento fino ad ora sviluppata.
Applicabilità
Oracle9i: Per quello che riguarda l’applicabilità, la tecnologia OR si presta bene a tutte le
applicazioni OO;
Versant: Per le applicazioni OO non c’è dubbio che la tecnologia dei OODBMS sia migliore in
quanto una mappatura trasparente è sempre preferibile ad una attuata dall’utente; in ogni caso, per il
fatto che gli OR sono da più tempo sul mercato, molte organizzazioni ritengono più sicuro l’utilizzo
di una tecnologia OR.
Trasparenza
Oracle9i: La trasparenza per questo prodotto viene a mancare in quanto è compito dello
sviluppatore aggiornare le associazioni tra gli oggetti attraverso i comandi SQL.
Versant: Per quanto riguarda questo prodotto, la trasparenza è ottenuta memorizzando e
rintracciando gli oggetti senza una query esplicita.
Un dato che si può riscontrare non dall’analisi delle tecnologie, ma dallo sviluppo dell’applicazione,
è il numero delle righe di codice scritte nelle due diverse implementazioni; Questo dato deve essere
preso con le dovute considerazioni; in primo luogo la complessità dell’applicazione, che non è
elevata; in secondo luogo la dimensione dell’applicazione(sempre non elevata); forse è anche per
questi motivi che il dato sul risparmio di codice scritto non è congruente con quello più volte
incontrato in letteratura che esprimeva la riduzione di codice stesso in termini di un 30/40 %. Da
una nostra analisi, il dato del risparmio è risultato circa del 12% (Fig. 7-1).
3300
3200
3100
Righe di
3000
codice
Versant
Oracle9i
2900
2800
2700
1
Implementazione
Fig. 7-1. Numero righe di codice nelle due implementazioni
63
Le nostre impressioni sono legate alla facilità di programmazione unita all’approccio abituale che si
aveva. Siamo stati quindi condizionati da una specie di stato iniziale, indotto praticamente dalla
conoscenza abbastanza approfondita solo della tecnologia OR, o meglio ancora solo della
tecnologia relazionale pura.
Nonostante questo, il beneficio nell’utilizzo del prodotto OO, ha portato ad un approccio
completamente diverso facendoci arrivare a considerare gli oggetti persistenti come oggetti già
istanziati dal programma. Le modifiche alle strutture dati si sono rivelate molto più trasparenti
siccome per quello che riguarda Versant una volta modificato l’oggetto di interesse, le modifiche si
propagano fino al livello di persistenza.
La capacità di apprendimento è risultata alta in quanto è solamente il linguaggio utilizzato ad
introdurre livelli di difficoltà(nel nostro caso Java).
Per concludere, l’elaborato non ha scandagliato tutti gli aspetti delle tecnologie in esame; la ragione
di questo è che sono meno significativi dal punto di vista del confronto OO/OR. In ogni caso i
principali argomenti solo accennati sono stati la gestione delle transazioni, la scabilità, la portabilità
e l’interoperabilità.
64
Bibliografia
[1] Atzeni P., Ceri S., Paraboschi S., Torlone R. Basi di dati. Milano, McGraw-Hill 1999
[2] Hamilton G., Cattell R., Fisher M. JDBC Database Access with Java. 1997
[3] Scott K. UML Explained. Milano, Addison-Wesley 2001
[4] Database Installation Guide. ORACLE. Giugno 2001
[5] Database Getting Started. ORACLE. Giugno 2001
[6] Simple Strategies for Complex Data. ORACLE. Maggio 2002
[7] Database Fundamentals Manual. VERSANT. Giugno 2003
[8] JVI Usage Manual. VERSANT. Giugno 2003
[9] Objects End-to-End The ODBMS Advantage. VERSANT. Giugno 2003
[10] Which Database is Right for the New Information Systems. VERSANT.
[11] “Estensione del modello relazionale e DBMS Object Relational”,
http://www.di.unico.it/∼giolito/Si202/bc07.pdf
[12] “PL/SQL Object Types”, http://oracle.cis.ksu.edu/DOC/appdev.901/a89856/10_objs.htm
[13] “SQL3 Object Model”, http://www.objs.com/x3h7/sql3.htm
[14] “Object Database Systems”, http://www.ipipan.waw.pl/∼subieta/objbases/ObjBases.html
[15] “Object Database vs. Object-Relational Databases”,
http://ca.com/products/jasmine/analyst/idc/14821E.htm