Il 0% ha trovato utile questo documento (0 voti)
10 visualizzazioni113 pagine

SQL Applicazioni

Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
10 visualizzazioni113 pagine

SQL Applicazioni

Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Sei sulla pagina 1/ 113

SQL per le applicazioni

Sommario
• SQL: caratteristiche evolute
– Funzioni scalari
– Transazioni
• SQL per le applicazioni
SQL: Caratteristiche evolute
Funzioni scalari
• Oltre alle funzioni aggregate di cui abbiamo già
parlato, SQL mette a disposizione diverse funzioni
scalari
• Possono essere utilizzate all’interno delle
espressioni del linguaggio
• Ricevono come argomento una o più espressioni
del linguaggio ciascuna delle quali restituisce valori
di un dominio elementare per ogni tupla su cui si
valuta la query
• Restituiscono un valore per ogni tupla
Famiglie di funzioni

• SQL-2 offre alcune famiglie di funzioni

• I DBMS commerciali spesso arricchiscono le varie


famiglie
Funzioni temporali
• Funzioni per la gestione degli attributi di tipo
“temporale” (date, time, timestamp)
• SQL-2 prevede:
– current_date
– current_time
– current_timestamp
– extract per isolare i vari campi (year, month,
day,…)
• Es. di altre funzioni: age
Funzioni su stringhe
• Funzioni per la manipolazione di stringhe
• SQL-2 prevede varie funzioni quali ad esempio:
– char_length
– lower
– upper
– substring
Funzioni di conversione
• SQL-2 prevede la funzione cast per convertire un
valore di un dominio in un valore di un altro
dominio.
• Es:
– cast(Data as char(10))
Funzioni non previste da SQL-2
• I DBSM offrono tipicamente altre famiglie di funzioni
non previste da SQL-2. Ad esempio:
– Funzioni matematiche
– Funzioni per la formattazione dell’output
– Funzioni per l’interazione con il sistema operativo
Funzioni condizionali
• Famiglia di funzioni prevista da SQL-2
• Contiene le funzioni: coalesce, nullif e
case
• Non arricchiscono il potere espressivo di SQL ma
semplificano la scrittura di alcune interrogazioni
coalesce
• Ammette come argomento una sequenza di
espressioni e restituisce il primo valore non nullo
• Permette quindi di convertire valori nulli in valori
espliciti
• Es:
SELECT Nome, Cognome,
coalesce(Dipart, „Ignoto‟) FROM
Impiegato
nullif
• Richiede come argomento un’espressione e un
valore costante; se l’espressione è uguale al valore
costante restituisce il valore nullo
• Svolge un ruolo complementare a quello della
funzione coalesce
• Es:
SELECT Nome, Cognome,
nullif(Dipart, „Ignoto‟) FROM
Impiegato
case
• Permette di specificare strutture condizionali, il cui
risultato dipende dal contenuto delle tabelle
• Prima variante:
case Espressione
when Valore then EsprRisultato
{when Valore then EsprRisultato}
[else EsprRisultato]
end
• restituisce risultati diversi a seconda dei diversi
valori assunti da Espressione
case
• Seconda variante:
Case when Condizione then EsprRisultato
{when Condizione then EsprRisultato}
[else EsprRisultato]
end
• restituisce risultati diversi in base al verificarsi di
diverse condizioni
case: esempi
• VEICOLO(Targa, Tipo, Anno, KWatt, Lunghezza,
Nassi)
select Targa
case Tipo
when „Auto‟ then 2.58*Kwatt
when „Moto‟ then (22.0+1.00*KWatt)
else null
end as Tassa
from Veicolo
where Anno > 1975
case: esempi
update Impiegato
set Stipendio =
case
when (Dipart=„Amministrazione‟ and
Ufficio=10) then Stipendio *1.1
when (Dipart=„Amministrazione‟ and
Ufficio <> 10) then Stipendio *1.2
when Dipart=„Produzione‟then
Stipendio *1.5
else Stipendio
end
SQL Per le applicazioni
SQL per le applicazioni
• Tipicamente l’interazione con le basi di dati avviene
per mezzo di applicazioni integrate nel sistema
informativo, in quanto:
– Spesso chi interagisce non è un utente ma
un’applicazione non interattiva
– Anche nel caso di utenti le modalità di interazione sono
semplici e prevedibili
SQL per le applicazioni
• Si viene incontro all’esigenza di un’interazione
basata su applicazioni in due modi:
– Estensione del linguaggio SQL per poter aggregare
diverse azioni
• Procedure
• Trigger
– Utilizzo di SQL nell’ambito dei linguaggi di
programmazione ad alto livello:
• SQL embedded
• Call level interface
Procedure
Procedure
• SQL-2 prevede la definizione di procedure (stored
procedures)
• Permettono di associare un nome ad una istruzione
SQL con la possibilità di specificarne parametri
• Vantaggi:
– Comprensibilità
– Manutenibilità
– Efficienza
Procedure
• In SQL-2 era prevista la possibilità di definire
procedure consistenti di un solo comando SQL
• In SQL-3 è stata ampliata la sintassi per la
definizione di procedure
• Sono state aggiunte strutture di controllo (istruzioni
condizionali, cicli, ecc. ) le possibilità di definire
variabili locali e altro
• I sistemi commerciali tipicamente hanno soluzioni
proprietarie e aderiscono poco o nulla allo standard
Procedure: un esempio
procedure AssegnaCitta(:Dip
varchar(20), :Citta varchar(20))
update Dipartimento
set Città = :Citta
where Nome = :Dip;
• La procedura può poi essere richiamata tramite un
opportuno comando (execute, call)
associando un valore ai parametri
Procedure: un altro esempio
procedure CambiaCittaATutti(:NuovaCitta
varchar(20), :VecchiaCitta varchar(20))
begin
update Dipartimento
set Città = :NuovaCitta
where Città = :VecchiaCitta;
update Impiegato
set Città = :NuovaCitta
where Città = :VecchiaCitta;
end;
Procedure: strutture di controllo
procedure CambiaCittaADip(:NomeDip
varchar(20),:NuovaCitta varchar(20))
if not exists (select *
from Dipartimento
where Nome=:NomeDip)
insert into ErroriDip values(:NomeDip)
else
update Dipartimento
set Città = :NuovaCitta
where Nome = :NomeDip;
end if;
end;
Trigger
Trigger
• I trigger sono azioni che vengono eseguite
automaticamente dal DBMS quando si verifica un
certo evento
• Sono chiamati anche regole attive
• Seguono il paradigma Evento-Condizione-Azione
• Rappresentano le reazioni che il sistema deve
compiere a seguito del verificarsi di alcune
condizioni
Trigger
• I trigger sono stati standardizzati a partire da SQL-3
• Esistevano nei sistemi commerciali da molto tempo
prima
• Lo standard non è ancora diffuso
Trigger: un esempio
create trigger ImpiegatiSenzaDip
after insert into impiegati
for each row
when (new.Dipart is null)
update Impiegati
set Dipart = „NuoviArrivati‟
where Matr=new.Matr
Trigger: un esempio
create trigger ImpiegatiSenzaDip
after insert into impiegati evento
for each row
when (new.Dipart is null) condizione
update Impiegati
set Dipart = „NuoviArrivati‟
azione
where Matr=new.Matr
Trigger
• Struttura sintattica in SQL-3:
– La parte evento può presentare solo operazioni SQL di
aggiornamento (insert, delete, update)
– Ogni trigger è sensibile ad un solo evento
– La parte condizione è un qualsiasi predicato SQL
– La parte azione è rappresentata da un singolo comando
SQL o da una procedura SQL
– Nella condizione e nell’azione si possono usare due
variabili predefinite new e old che fanno riferimento
alla nuova e alla vecchia versione della tupla
Trigger: perché?
• Servono per gestire vincoli generici:
– Reagiscono ad eventi che possono violare un vincolo
– Verificano se il vincolo è stato violato
– Correggono l’errore
• Consentono di reagire alla introduzione di errori
senza impedire l’esecuzione dell’operazione
Trigger: problemi
• Può essere difficile gestire un sistema con molti
trigger:
– L’esecuzione di un trigger può causare l’attivazione di
un altro trigger
– Si possono generare loop infiniti nel caso di trigger che
si attivano mutuamente in modo ciclico
SQL Embedded
SQL Embedded
• Le istruzioni SQL vengono introdotte direttamente
nel programma
• Vengono distinte per mezzo di un opportuno
separatore
• Lo standard SQL prevede che il codice SQL sia
preceduto dalla stringa exec sql e termini con
il punto e virgola
SQL Embedded
• Prima di compilare il programma occorre invocare
un preprocessore che si preoccuperà di sostituire
alle istruzioni SQL un insieme opportuno di
chiamate a servizi del DBMS tramite una libreria
specifica per ogni sistema
• Il preprocessore segnala anche eventuali errori
nell’uso di SQL
• È necessario un preprocessore per ogni
combinazione DBMS-Piattaforma-Linguaggio-
Compilatore
SQL Embedded: esempio
#include<stdlib.h>
main(){
exec sql begin declare section;
char *NomeDip = “Manutenzione”;
char *CittaDip = “Pisa”;
int NumeroDip = 20;
exec sql end declare section;
exec sql connect to utente@librodb;
if(sqlca.sqlcode != 0){
printf(“Connessione al DB non riuscita\n”);}
else{
exec sql insert into Dipartimento values(:NomeDip,
:CittaDip, :NumeroDip);
exec sql disconnect all;}
}
SQL Embedded: esempio
• L’esempio precedente fa riferimento al
preprocessore ECPG per il linguaggio C e il DBMS
PostgreSQL
• La struttura sqlca (SQL Communication Area)
permette di gestire la comunicazione tra il
programma e il DBMS
• Il campo sqlcode di tale struttura memorizza il
codice di errore dell’ultimo comando SQL
SQL Emebedded: problema
• I linguaggi di programmazione accedono agli
elementi di una tabella scandendo le righe una a
una (approccio tuple-oriented)
• SQL opera su tabelle e non su righe (approccio set-
oriented)
• Due soluzioni:
– Cursori
– Uso di strutture dati che possano gestire tabelle intere
(sempre più diffuso nei linguaggi object-oriented)
Cursori: definizione
• Un cursore è uno strumento che permette ad un
programma di accedere alle righe di una tabella una
alla volta
• Definizione di un cursore
declare NomeCursore [scroll] cursor for
SelectSQL
[for < read only | update [ of Attributo{,
Attributo}]>]
Cursori: definizione
• L’opzione scroll specifica se si vuole
permettere la possibilità di muoversi liberamente tra
le varie tuple
• L’opzione for update specifica se il cursore
deve essere utilizzato in un comando di modifica,
permettendo di indicare gli attributi da modificare
Cursori: uso
• Esecuzione dell’interrogazione
open NomeCursore
• Scansione dei risultati
fetch [Posizione from] NomeCursore into
ListaDiFetch
– ListaDiFetch è una lista di variabili del programma (una
per ogni elemento della target list) in cui verranno
memorizzati i valori della target list della riga corrente
– Posizione indica la riga che sarà oggetto
dell’operazione di fetch
Cursori: uso
• Possibili valori per Posizione:
– next (riga successiva), prior (riga precedente),
first (prima riga), last (ultima riga)
– absolute EspressioneIntera (la riga k-esima,
essendo k il risultato dell’espressione)
– relative EspressioneIntera (la riga k posizioni
dopo la corrente, essendo k il risultato dell’espressione)
• Senza l’opzione scroll l’unico valore possibile è
next
Cursori: update e delete
• È possibile aggiornare e cancellare la riga corrente
del cursore come segue:
update NomeTabella
set Attributo=<Espressione|null|default>
{,Attributo=<Espressione|null|default>}
where current of NomeCursore

delete from NomeTabella where current of


NomeCursore
Cursori: chiusura
• Le risorse associate al cursore vengono rilasciate
quando questo non serve più tramite il comando
close NomeCursore
Cursori: esempio
void VisualizzaStipendiDipart(char NomeDip[]){
exec sql begin declare section;
char Nome[20], Cognome[20];
long int Stipendio;
exec sql end declare section;
exec sql declare ImpDip cursor for
select Nome, Cognome, Stipendio
from Impiegato
where Dipart = :NomeDip;
exec sql open ImpDip;
exec sql fetch ImpDip into :Nome, :Cognome, :Stipendio;
printf(“Dipartimento %s\n”,NomeDip);
while(sqlca.sqlcode == 0){
printf(“Nome e Cognome dell‟Impiegato: %s %s”,Nome,Cognome);
printf(“Attuale Stipendio: %d\n”,Stipendio);
exec sql fetch ImpDip into :Nome, :Cognome, :Stipendio;
}
exec sql close cursor ImpDip;
}
Cursori: Query scalari
• Se l’interrogazione restituice una sola tupla si può
memorizzare il risultato all’interno di varaibili del
programma senza l’uso dei cursori:
select Nome, Cognome into :nomeDip,
:cognomeDip
from Dipendente
where Matricola = :MatrDip;
SQL Dinamico
SQL Dinamico
• Negli esempi visti finora le interrogazioni avevano
una struttura fissa e durante l’esecuzione del
programma potevano cambiare soltanto i parametri
(SQL statico)
• Può essere necessario definire a tempo di
esecuzione la struttura stessa dell’interrogazione
• È possibile farlo utilizzando l’SQL dinamico
SQL Dinamico
• Con l’SQL dinamico le istruzioni SQL vengono
definite a tempo di esecuzione
• Non è possibile un preprocessamento
• L’interrogazione deve essere analizzata e
ottimizzata ogni volta che si richiede la sua
esecuzione
• Con SQL dinamico sono possibili due modalità di
esecuzione
SQL Dinamico: esecuz. immediata
• Con il comando execute immediate si
chiede l’esecuzione immediata di una istruzione
SQL specificata come stringa
execute immediate IstruzioneSQL
• È possibile solo con interrogazioni che non
prevedono parametri di ingresso né di uscita (alcuni
inserimenti o cancellazioni)
Esecuz. Immediata: esempi
exec sql execute immediate “delete
from Impiegato where Nome
=„Mario‟”;
___________________________________
istruzioneSql=“delete from
Impiegato where Nome=„Mario‟”

exec sql execute immediate
:istruzioneSQL
SQL Dinamico: preparaz. e esecuz.
• Se l’interrogazione richiede parametri di ingresso o
uscita è necessario distinguere la fase di
preparazione da quella di esecuzione
prepare NomeComando from IstruzioneSQL
• Associa all’istruzione un nome che viene poi usato
per eseguire l’istruzione
• L’istruzione può contenere parametri di ingresso
rappresentati dal carattere ?
prepare :comando from “select Città
from Dipartimento where Nome=?”
SQL Dinamico: preparaz. e esecuz.
• Per eseguire un comando “preparato”:
execute NomeComando [into ListaTarget]
[using ListaParametri]
• ListaTarget è la lista di variabili in cui viene scritto il
risultato (opzionale)
• ListaParametri è la lista dei valori che devono
essere assunti dai parametri di ingresso (opzionale)
Esecuzione: esempio
dipartimento = “Produzione”;
execute :comando into :citta using
:dipartimento
• Equivale a:
select Città from Dipartimento
where Nome=„Produzione‟
SQL Dinamico: deallocazione
• Quando un comando preparato non serve più si
può liberare la memoria ad esso associata con il
comando deallocate prepare:
deallocate prepare NomeComando
SQL Dinamico: cursori
• L’uso dei cursori è simile al caso statico
• Le differenze sono:
– Il cursore è associato al nome dell’istruzione e non
all’istruzione stessa
– Il comando open ammette l’uso della clausola using
che permette di specificare i parametri di ingresso
prepare :comando from :istruzioneSQL
declare Cursore cursor for :comando
open Cursore using :nome1
Call Level Interface (CLI)
Call Level Interface
• Le soluzioni basate su CLI mettono a disposizione
del programmatore una libreria di funzioni che
consentono di interagire direttamente con il DBMS
• Rispetto alla soluzione SQL embedded risulta più
flessibile, richiede di gestire aspetti che in SQL
embedded sono risolti dal preprocessore
Call Level Interface
• La modalità generale d’uso di CLI è la seguente:
– Si utilizza un servizio della CLI per creare una
connessione verso il DBMS
– Si invia un comando SQL sulla connessione
– Si riceve come risposta una struttura relazionale in un
opportuno formato
– Al termine della sessione di lavoro si chiude la
connessione
Call Level Interface
• Esistono diverse soluzioni per sistemi e linguaggi
diversi:
– Ambiente Microsoft: ODBC, OLE DB, ADO, ADO.NET
– Java: JDBC
ODBC
• Open DataBase Connectivity
• Interfaccia applicativa per l’accesso alle basi di dati
• Proposta originariamente dalla Microsoft poi
divenuta uno standard
• L’obbiettivo di ODBC è permettere la realizzazione
di applicazioni che facciano accesso a basi di dati
relazionali di tipo eterogeneo eventualmente
accessibili tramite la rete
• Il linguaggio supportato da ODBC è un SQL ristretto
ODBC
• Il collegamento tra l’applicazione e un server
avviene mediante l’uso di un driver
• Un driver è una libreria dinamica utilizzata
dall’applicazione
• Il driver maschera le differenze di interazione legate
al DBMS, al sistema operativo e al protocollo di rete
specifici
• Un driver è quindi definito dalla tripla DBMS,
Sistema Operativo, Protocollo di rete
ODBC
• L’accesso alla base di dati tramite ODBC richiede la
cooperazione di quattro componenti di sistema
• L’applicazione: usa l’SQL per eseguire
interrogazioni e acquisirne i risultati. Dettagli sul
protocollo di comunicazione, DBMS e sistema
operativo sono mascherati dal driver
• Il driver manager: carica i driver su richiesta
dell’applicazione
ODBC
• Il driver: implementa le funzioni ODBC. Sa eseguire
codice SQL adattandolo allo specifico prodotto. È
responsabile di restituire i risultati tramite
meccanismi di buffering
• La fonte dei dati (data source): è il sistema che
effettivamente esegue le operazioni trasmesse dal
client. Tipicamente è un DBMS
ODBC
• In ODBC i messaggi di errore sono standardizzati
• Le interrogazioni possono essere specificate in
modo statico oppure generate ed eseguite
dinamicamente
• ODBC è abbastanza complesso per essere
utilizzato direttamente dal programmatore
• Per questo Microsoft ha sviluppato altre soluzioni
che, innalzando il livello di astrazione, semplificano
la creazione di applicazioni
OLE DB
• Object Linking and Embedding for DataBases
• Interfaccia generale per l’accesso a sorgenti dati di
tipo generico (non solo sistemi relazionali)
• Si basa sul modello a oggetti COM
• A seconda della sorgente utilizzata sarà possibile o
meno usare determinati servizi
• Se la sorgente è di tipo relazionale OLE DB si
appoggia su ODBC
ADO
• ActiveX Data Object
• Interfaccia ad alto livello per i servizi offerti da OLE
DB
• È utilizzabile nei diversi linguaggi di
programmazione offerti dalla piattaforma Microsoft
(Visual C++, Visual Basic, VBScript, Jscript)
ADO
• Si basa su quattro concetti fondamentali:
– La connessione (Connection): canale di comunicazione
con la sorgente dati. Viene creato specificando
l’indirizzo del sistema, username e password
– Il Comando (Command): rappresenta la stringa che
contiene l’istruzione che si vuole far eseguire alla
sorgente dati
– La tupla (Record): singola riga di una tabella. Offre
strumenti per riconoscere la struttura della tupla
– L’insieme di tuple (RecordSet): memorizza il risultato
dell’interrogazione e offre meccanismi per scandirlo
ADO: esempio in VisualBasic
Public Sub InterrogaDB()
Dim setImpiegati As ADODB.Recordset
Dim conn As ADODB.Connection
Dim stringaSQL As String
Dim comSQL as ADODB.Command
Dim arrImpiegati As Variant
Dim messaggio As String
Dim numRighe As Integer
Set conn=New ADODB.Connection
conn.Open “mioServer”, “giovanni”, “passwordsegreta”
Set setImpiegati = New ADODB.Recordset
stringaSQL = “select Nome, Cognome, Data” _
“from Impiegato order by Cognome”
comSQL.CommandText = stringaSQL

ADO: esempio in VisualBasic
setImpiegati.Open comSQL, conn, , ,
Do While Not setImpiegati.EOF
messaggio = “Impiegato: ” & setImpiegati!Nome &_
setImpiegati!Cognome & “(record ” & _
setImpiegati.AbsolutePosition & _
“ di ” & setImpiegati.RecordCount & “)”
If MsgBox(messaggio, vbOKCancel) = vbCancel
Then Exit Do
setImpiegati.MoveNext
Loop
setImpiegati.Close
conn.Close
Set setImpiegati = Nothing
Set conn = Nothing
End Sub
ADO.NET
• Evoluzione di ADO per operare nella piattaforma
.NET
• Non è un semplice adattamento di ADO ma
presenta differenze sostanziali
ADO.NET vs ADO
• In ADO l’oggetto principale per il dialogo con il DB è
il RecordSet che viene gestito tramite connessione
dirette con la base di dati
• L’accesso al RecordSet avviene con strumenti simili
ai cursori
• In ADO.NET si hanno invece i DataSet che
rappresentano contenitori di oggetti (tra cui i
DataTable che rappresentano le normali tabelle)
• L’accesso ai dati nei DataSet avviene secondo i
meccanismi di accesso a collezioni di oggetti
ADO.NET vs ADO
• Un’altra differenza è che ADO.NET è che un
DataSet consente la gestione di vincoli di integrità
tra gli oggetti al suo interno
• Ciò è possibile perché i DataSet sono strutture che
risiedono completamente nell’ambiente del
programma
• In ADO invece il risultato di una query viene
mantenuto nel contesto della sessione con il DB ed
è disponibile tupla per tupla al momento della
scansione
ADO.NET vs ADO
• Il coordinamento tra DataSet e le sorgenti di dti
avviene tramite i DataAdapter
• Esistono diverse specializzazioni della classe
DataAdapter a seconda delle caratteristiche della
sorgente dati (SqlDataAdapter, OledbDataAdapter,
OdbcDataAdpter,…)
DataAdapter
• I metodi principali di DataAdapter sono:
– fill: carica i dati dalla sorgente di dati e li trasferisce nel
DataSet
– update: aggiorna la sorgente riportando le modifiche
effettuate sul DataSet
• L’uso dei metodi fill e update:
– maschera completamente l’interazione con il database
– riduce il numero di connessioni contemporaneamente
attive
JDBC
• JDBC è l’API Java per l’accesso alle basi di dati
• Permette di accedere in modo uniforme a basi di
dati relazionali mascherando le differenze dovute
agli specifici sistemi (simile a ODBC)
• L’architettura JDBC prevede la presenza di un
driverManager che separa l’applicazione dal
componente che implementa il servizio
• Esistono quattro diverse architetture
JDBC tipo 1: Driver Nativo
JVM
• Prevede di tradurre le
richieste JDBC in richieste
Java Application
ad un driver in codice nativo
• Il driver nativo è specifico JDBC Driver Manager
per il DBMS che si sta
utilizzando Bridge JDBC/Nativo
• ed è realizzato per
consentire l’accesso al
Driver nativo
DBMS da parte di
programmi scritti in
linguaggi di alto livello DBMS
JDBC tipo 2: Bridge JDBC/ODBC
JVM
• Prevede di tradurre le
richieste JDBC in richieste
Java Application
al driver manager ODBC
• È necessario che la JDBC Driver Manager
macchina sia dotata di un
driver ODBC per lo Bridge JDBC/ODBC
specifico DBMS
ODBC Driver

DBMS
JDBC tipo 3: Middleware server
• Prevede l’uso di un server
JAVA che traduce le JVM
richieste provenienti dal
driver manager nel formato Java Application
riconosciuto dallo specifico
DBMS JDBC Driver Manager
• Esistono prodotti che
realizzano funzioni di JDBC Middleware
questo tipo permettendo di (vari DBMS)
interagire con diversi DBMS
DBMS
JDBC tipo 4: Driver Java
• Prevede l’uso di un driver
JAVA per lo specifico JVM
DBMS
Java Application

JDBC Driver Manager


JDBC Driver
(specifico DBMS)

DBMS
JDBC: uso
• Per utilizzare JDBC si opera secondo i seguenti
passi:
– Si carica il driver richiesto
– Si crea una connessione con il DB
– Si compone un comando SQL e lo si invia alla base di
dati
– Si gestisce il risultato
JDBC: esempio
import java.sql.*;
public class PrimoJdbc{
public static void main(String[] args){
Connection conn=null;
try{
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
conn=DriverManager.getConnection(“jdbc:odbc:Corsi”)
Statement interrogazione=conn.createStatement();
ResultSet risultato=interrogazione.executeQuery(
“select * from corsi”);
while(risultato.next()){
String nomeCorso=risultato.getString(“NomeCorso”)
System.out.println(nomeCorso);
}
} catch (Exception e){System.exit(1);}
}
}
JDBC: la connessione
• Per ottenere una connessione al DB si usa il
metodo statico getConnection della classe
DriverManager al quale va passato un indirizzo nel
seguente formato:
jdbc:subprotocol:subname
– subprotocol: dipende dallo specifico DBMS
– subname: indirizzo del DB (di solito il nome)
• Il metodo getConnection può ricevere anche una
username e una password
JDBC: la connessione
import java.sql.*;
public class PrimoJdbc{
public static void main(String[] args){
Connection conn=null;
try{
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
conn=DriverManager.getConnection(“jdbc:odbc:Corsi”)
Statement interrogazione=conn.createStatement();
ResultSet risultato=interrogazione.executeQuery(
“select * from corsi”);
while(risultato.next()){
String nomeCorso=risultato.getString(“NomeCorso”)
System.out.println(nomeCorso);
}
} catch (Exception e){System.exit(1);}
}
}
JDBC: la classe Statement
• Uno oggetto Statement si ottiene (di solito)
invocando il metodo createStatement della classe
Connection
• I metodi principali della classe Statement sono:
– executeQuery: per eseguire una istruzione SELECT
– executeUpdate: per eseguire una istruzione INSERT,
DELETE, UPDATE
JDBC: la classe Statement
import java.sql.*;
public class PrimoJdbc{
public static void main(String[] args){
Connection conn=null;
try{
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
conn=DriverManager.getConnection(“jdbc:odbc:Corsi”)
Statement interrogazione=conn.createStatement();
ResultSet risultato=interrogazione.executeQuery(
“select * from corsi”);
while(risultato.next()){
String nomeCorso=risultato.getString(“NomeCorso”)
System.out.println(nomeCorso);
}
} catch (Exception e){System.exit(1);}
}
}
JDBC: la classe PreparedStatement
• Uno oggetto PreparedStatement serve a creare
interrogazioni parametriche
• ottiene (di solito) invocando il metodo
prepareStatement della classe Connection
• I metodi principali della classe Statement sono:
– executeQuery: per eseguire una istruzione SELECT
– executeUpdate: per eseguire una istruzione INSERT,
DELETE, UPDATE
– setXXX: per settare i parametri (esiste un metodo per
ogni tipo)
JDBC: la classe PreparedStatement
...
PreparedStatement updateSales = con.prepareStatement( "UPDATE
COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
...
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();

• È equivalente a:

String updateString = "UPDATE COFFEES SET SALES = 75 " +


"WHERE COF_NAME LIKE 'Colombian'";
stmt.executeUpdate(updateString);
JDBC: la classe ResultSet
• Uno oggetto della classe ResultSet realizza un
cursore
• All’atto della creazione di uno Statement (o
PreparedStatement) si può indicare il tipo di
ResultSet restituito:
– TYPE_FORWARD_ONLY: può essere scorso solo in
avanti (default)
– TYPE_SCROLL_INSENSITIVE: può essere scorso
– TYPE_SCROLL_SENSITIVE: può essere scorso
JDBC: la classe ResultSet
• Può essere inoltre indicata la modificabilità dei dati
sottostanti:
– CONCUR_READ_ONLY: i dati nel ResultSet non
possono essere modificati (default)
– CONCUR_UPDATABLE: i dati nel ResultSet possono
essere modificati
• Se si specifica il tipo del ResultSet bisogna
specificare anche la modificabilità
JDBC: la classe ResultSet
• Metodi per scandire i dati nel RecordSet:
– next
– previous
– first
– last
– beforeFirst
– afterLast
– relative
– absolute
JDBC: la classe ResultSet
• L’accesso ai campi di ciascuna tupla avvengono
mediante metodi:
– getBoolean
– getInt
– getFloat
– …
• Ognuno di tali metodi può prendere come
parametro:
– Una stringa (il nome dell’attributo nella target list)
– Un indice (la posizione dell’attributo di interesse)
JDBC: la classe ResultSet
import java.sql.*;
public class PrimoJdbc{
public static void main(String[] args){
Connection conn=null;
try{
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
conn=DriverManager.getConnection(“jdbc:odbc:Corsi”)
Statement interrogazione=conn.createStatement();
ResultSet risultato=interrogazione.executeQuery(
“select * from corsi”);
while(risultato.next()){
String nomeCorso=risultato.getString(“NomeCorso”)
System.out.println(nomeCorso);
}
} catch (Exception e){System.exit(1);}
}
}
JDBC: la classe ResultSet
Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery( "SELECT COF_NAME, PRICE FROM
COFFEES");
while (srs.next()){
String name = srs.getString("COF_NAME");
float price = srs.getFloat("PRICE");
System.out.println(name + " " + price);
}
JDBC: la classe ResultSet
Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery( "SELECT COF_NAME, PRICE FROM
COFFEES");
while (srs.next()){
String name = srs.getString(1);
float price = srs.getFloat(2);
System.out.println(name + " " + price);
}
JDBC: la classe ResultSet
Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery( "SELECT COF_NAME, PRICE FROM
COFFEES");
srs.afterLast()
while (srs.previous()){
String name = srs.getString(1);
float price = srs.getFloat(2);
System.out.println(name + " " + price);
}
Transazioni
Definizione di transazioni
• SQL mette a disposizione i seguenti comandi per
gestire le transazioni:
– start transaction
– commit work
– rollback work
Definizione di transazioni
• start transaction indica l’inizio della
transazione
• commit work rende effettive le modifiche
effettuate dalla transazione
• rollback work annulla tutte le modifiche
effettuate dalla transazione
Transazioni
• La transazione va quindi a buon fine soltanto se
viene eseguito un commit
• La transazione non ha alcun effetto sullo stato della
base di dati se viene eseguito un rollback (abort)
• Una transazione è ben formata se inizia con start
transaction e durante la sua esecuzione viene
eseguito uno solo dei comandi commit work,
rollback work
Transazioni
• Es:
start transaction;
update ContoCorrente
set ammontare = Ammontare + 10
where NumConto=12202;
update ContoCorrente
set Ammontare=Ammontare – 10
where NumConto = 42177;
commit work;
Gestione della concorrenza in SQL
• Abbiamo visto che l’esecuzione concorrente di
transazioni può provocare delle anomalie
• Abbiamo visto varie soluzioni per evitare tali
anomalie, in particolare il locking a due fasi
• La gestione del locking è però costosa: se non
serve, possiamo rinunciarci
• In SQL è possibile “rinunciare” al controllo di
concorrenza definendo il livello di isolamento di
ciascuna transazione (solo per le letture)
Anomalie
• Perdita di aggiornamento W-W
• Lettura sporca R-W (o W-W) con
abort
• Letture inconsistentiR-W
• Aggiornamento fantasma R-W
• Inserimento fantasma R-W su dato "nuovo"
Transazioni di sola lettura
• Le transazioni possono essere definite read
only oppure read write (default)
• Le transazioni read only non possono
modificare la base di dati (né il contenuto né lo
schema)
• Tali transazioni vengono gestite con soli lock
condivisi
Livelli di isolamento
• Per ogni transazione può essere scelto uno tra i
seguenti livelli di isolamento:
– read uncommitted:
• nessun lock in lettura e non rispetta i lock esclusivi.
• Permette letture sporche, letture inconsistenti, aggiornamenti
fantasma e inserimenti fantasma. Di solito si usa insieme a
read only
– read committed:
• lock condivisi per le letture, rispetta i lock esclusivi, no 2PL.
• Evita letture sporche ma permette letture inconsistenti,
aggiornamenti fantasma e inserimenti fantasma
Livelli di isolamento
– repeatable read:
• 2PL stretto a livello di tupla.
• Evita tutte le anomalie esclusi gli inserimenti fantasma
– serializable:
• 2PL stretto e lock di predicati.
• Evita tutte le anomalie
• Nota:
– la perdita di aggiornamento è sempre evitata
Anomalie e livelli di isolamento
Perdita di aggiornamento W-W
•read uncommitted
Lettura sporca R-W (o W-W) con abort
•read committed
Letture inconsistenti R-W
Aggiornamento fantasma R-W
•repeatable read
Inserimento fantasma R-W su dato "nuovo"
•serializable
JDBC: transazioni
• Normalmente le istruzioni SQL vengono eseguite in
modalità auto-commit
• Per eseguire una transazione è necessario
disabilitare tale modalità tramite il metodo
setAutoCommit(boolean) della classe Connection
• Infine i cambiamenti possono essere resi effettivi o
annullati mediante i metodi commit() e rollback()
della classe Connection
JDBC: transazioni
con.setAutoCommit(false);
PreparedStatement updateSales = con.prepareStatement( "UPDATE
COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
updateSales.setInt(1, 50);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
PreparedStatement updateTotal = con.prepareStatement( "UPDATE
COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE ?");
updateTotal.setInt(1, 50);
updateTotal.setString(2, "Colombian");
updateTotal.executeUpdate();
con.commit();
con.setAutoCommit(true);
JDBC: transazioni
• È anche possibile annullare parzialmente una
transazione definendo dei punti di ripristino
• A tal fine esiste la classe Savepoint e il metodo
setSavepoint della classe connection
JDBC: transazioni
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +
"(?FIRST?)"); // set savepoint

Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");


rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " + "VALUES
(?SECOND?)");
...
conn.rollback(svpt1);
...
conn.commit();
JDBC: livelli di isolamento
• È possibile definire i livelli di isolamento della
transazione mediante il metodo
setTransactionIsolation della classe Connection
• I valori possibili sono:
– TRANSACTION_READ_UNCOMMITTED
– TRANSACTION_READ_COMMITTED
– TRANSACTION_REPEATABLE_READ
– TRANSACTION_SERIALIZABLE
– TRANSACTION_NONE

Potrebbero piacerti anche