Linee guida per la programmazione di transazioni in PL/SQL Giuseppe Berio Giuseppe Berio DI - Unito 1
Esempio La transazione deve registrare l evasione di un ordine, rappresentato su più tabelle specializzate per tipologia di prodotto, usando una tabella che contiene per ogni prodotto la quantità disponibile a magazzino. Naturalmente, ogni ordine non contiene necessariamente tutti i prodotti commercializzati dall azienda. Ogni ordine può essere evaso parzialmente, cioè se non vi è sufficiente quantità di un prodotto ma vi è sufficiente quantità di un altro, l ordine viene evaso solo relativamente a questo ultimo prodotto. Giuseppe Berio DI - Unito 2
Vi sono due tipi di prodotto Magazzino Cod_Prodotto Esempio Quantità Quantità >= 0, Un prodotto richiesto potrebbe non esistere, Un prodotto richiesto potrebbe avere quantità NULL Ordini1 Cod_Ordine Ordini2 Cod_Ordine Quantità Stato Quantità Stato Ordini distinti per tipologia di merce, Quantità >= 0 Giuseppe Berio DI - Unito 3
Declare quantità1 number; out, x1, x2 varchar2; errore_interno, quantitàindefinita, quantitàinsufficiente Exception; Begin select quantità into quantità1 from Magazzino where cod_prodotto=x1; Ifquantità1 IS NULL then RAISE quantitàindefinita; end if; when quantitàindefinita then quantità1:=0; when others then out:= errore ; If out= errore then RAISE errore_interno; end if; Commit; Exception When errore_interno then rollback; When others then rollback; End; Normale eccezione causata dalla possibilità che quantità sia NULL: non è necessario fare un rollback Giuseppe Berio DI - Unito 4
Declare quantità1, quantità2 number; out, x1, x2 varchar2; errore_interno, quantitàinsufficiente quantitàindefinita, Exception; Begin select quantità into quantità1 from Ordini1 where cod_ordine=x1; If quantità1 IS NULL then RAISE quantitàindefinita; end if; when no_data_found then quantità1:=0; when quantitàindefinita then quantità1:=0; when others then out:= errore ; If out= errore then RAISE errore_interno; end if; Commit; Exception When errore_interno then rollback; When others then rollback; Non è necessario fare un rollback Eccezioni per cui è necessario rimandare la gestione al livello di annidamento inferiore : in tal caso si decide per un rollback End; Giuseppe Berio DI - Unito 5
Commento Trasparente 4 selectquantità into quantità1 frommagazzino where cod_prodotto=x1; Trasparente 5 select quantità into quantitàord1 from Ordini1 where cod_ordine=x1; Ifquantità1<= quantitàord1 then RAISE quantitàinsufficiente; end if; Il test non ha senso se non si controlla la concorrenza Giuseppe Berio DI - Unito 6
Declare Begin. Savepoint S1; Evasione parziale di Ordini Update Magazzino set quantità= quantità-quantità1 where cod_prodotto=y1; when others then out:= impossibilevadere ; If out = impossibilevadere then rollback to S1; end if; Savepoint S2; Update Magazzino set quantità= quantità-quantità2 where cod_prodotto=y2; when others then out := impossibilevadere ; If out = impossibilevadere then rollback to S2; end if; Commit; End; Il vincolo Quantità>=0 è initially immediate, immediate (default di Oracle) Eccezioni per cui è necessario fare un rollback parziale in quanto si permette di evadere parzialmente un ordine Giuseppe Berio DI - Unito 7
Confusione delle Eccezioni Select quantità into quantità1 from Ordini1 where cod_ordine=x1; Update Ordini1 set stato= evaso where cod_ordine=x1; Update Magazzino set quantità=quantità-quantità1 where cod_prodotto=y1; When no_data_found then quantità1:=0; When others then quantità1:=0; Necessario usare sqlcode oppure la tracciatura delle eccezioni in when then. La soluzione potrebbe dare luogo ad una confusione delle eccezioni: No_data_found e others potrebbero gestire (allo stesso modo) eccezioni distinte causate da più istruzioni Giuseppe Berio DI - Unito 8
Ordine delle Istruzioni Select quantità into quantità1 from Ordini1 where cod_ordine=x1; Update Magazzino set quantità=quantità-quantità1 where cod_prodotto=y1; Update Ordini1 set stato= evaso where cod_ordine=x1; When no_data_found thenquantità1:=0; When others thenquantità1:=0; La soluzione indicata dovrebbe essere indipendente dall ordine delle istruzioni che operano sulla basedati e che sono indipendenti Giuseppe Berio DI - Unito 9
Vincoli Immediati e Differiti Vincolo immediato e differibile: default Create table A (a number(10) check(a>0) initially immediate deferrable); Vincolo differito e differibile Create table A (a number(10) check(a>0) initially deferred deferrable); Giuseppe Berio DI - Unito 10
Evasione Ordini tutto o niente Modifica del precedente esercizio La richieste è ora: o un ordine è evaso completamente oppure non è evaso per niente In altre parole, se un ordine prevede prodotti distinti, tutti questi prodotti devono essere disponibili nel magazzino nelle quantità richieste Giuseppe Berio DI - Unito 11
Declare Begin Evasione Ordini tutto o niente I Update Magazzino set quantità= quantità-quantità1 where cod_prodotto=y1; when others then out:= impossibilevadere ; If out= impossibilevadere then RAISE quantitàinsuffciente end if; Update Magazzino set quantità= quantità-quantità2 where cod_prodotto=y2; when others then out := impossibilevadere ; If out= impossibilevadere then RAISE quantitàinsuffciente end if; Commit; Exception When quantitàinsuffciente then rollback; When others then rollback; End; Eccezioni per cui è necessario rimandare la gestione al livello di annidamento inferiore : in tal caso si decide per un rollback Giuseppe Berio DI - Unito 12
Declare Begin Commit; Exception Evasione Ordini tutto o niente II Update Magazzino set quantità= quantità-quantità1 where cod_prodotto=y1; When others then Update Magazzino set quantità= quantità-quantità2 where cod_prodotto=y2; When others then Il vincolo Quantità>=0 è initially deferred, deferrable. Ciò causa tuttavia alcune Per altre eccezioni è necessario rimandare la gestione al livello di annidamento inferiore : in tal caso si decide per un rollback When others then rollback; Giuseppe Berio DI - Unito inefficienze 13 End;
Declare Begin Exception Evasione parziale Ordini: uso di più commit Select quantità into quantità1 from Ordini1 where cod_ordine=x1; Update Ordini1 set stato= evaso where cod_ordine=x1; UpdateMagazzino set quantità=quantità-quantità1 where cod_prodotto=y1; Commit; When no_data_found then quantità1:=0; When others then quantità1:=0; Select quantità into quantità2 from Ordini2 where cod_ordine=x2; Update Ordini2 set stato= evaso where cod_ordine=x2; UpdateMagazzino set quantità= quantità-quantità2 where cod_prodotto=y2; Commit; When no_data_found then quantità2:=0; When others then quantità2:=0; Il vincolo Quantità>=0 è initially deferred, deferrable In questo caso i livelli di annidamento superiore agiscono da transazioni: in tal caso, i vincoli sono dichiarati come deferred e quindi controllati al primo commit. When others then rollback; Giuseppe Berio DI - Unito 14 End;
Vincoli e Codice dei Programmi Vincoli: parte dello schema della base dati Programmi: servono per programmare le transazioni E possibile far dipendere i programmi dai vincoli, anche se: I programmi diventano dipendenti dai vincoli; cosa accade se questi variano? I programmi risultano più efficienti, limitano il ricorso ad una gestione della concorrenza, ma diventano limitatamente modularizzabili; cosa accade se si usano procedure? Giuseppe Berio DI - Unito 15