Transazioni
Transcript
Transazioni
Tecnologie Web T Gestione delle Transazioni e Livelli di Isolamento Home Page del corso: http://www-db.disi.unibo.it/courses/TW/ Versione elettronica: 4.03.Transazioni.pdf Versione elettronica: 4.03. Transazioni-2p.pdf Gestione Transazioni 1 Introduzione Caratteristica di base delle nostre applicazioni Web è quella di avere un elevato numero di utenti che accedono, anche in maniera concorrente, ai dati (base di dati) verso i quali si interfacciano Il sistema di gestione dei dati (DBMS) deve garantire affidabilità e prestazioni la base di dati deve essere sempre in uno stato consistente La gestione della concorrenza e della affidabilità nell'accesso ai dati è una delle proprietà fondamentali che ci offrono i moderni DBMS Un concetto cardine è quello di transazione Gestione Transazioni 2 Transazioni Informalmente, una transazione è una sequenza di operazioni che può concludersi con un successo o un insuccesso in caso di successo: il risultato delle operazioni deve essere permanente in caso di insuccesso: si deve tornare allo stato precedente all'inizio della transazione Gestione Transazioni 3 Definizione di transazione Transazione parte di programma caratterizzata da un inizio (begin-transaction, start transaction in SQL), una fine (end-transaction, non esplicitata in SQL) e al cui interno deve essere eseguito una e una sola volta uno dei seguenti comandi: commit work per terminare correttamente rollback work per abortire la transazione Un sistema transazionale (OLTP) è in grado di definire ed eseguire transazioni per conto di un certo numero di applicazioni concorrenti Gestione Transazioni 4 Applicazioni e transazioni L'esecuzione di un programma può essere visto come una sequenza di transazioni (eventualmente intervallate da operazioni non relative ai dati) begin T1 AZIONI PROGRAMMA APPLICATIVO TRANSAZIONE T1 end T1 begin T2 AZIONI TRANSAZIONE T2 end T2 Gestione Transazioni 5 Una transazione SQL Esempio: “trasferimento di 10 unità dal conto 42177 al conto 12202” start transaction; update ContoCorrente set Saldo = Saldo + 10 where NumConto = 12202; update ContoCorrente set Saldo = Saldo - 10 where NumConto = 42177; commit work; Gestione Transazioni 6 Una transazione con varie decisioni Esempio: “trasferimento di 10 unità dal conto 42177 al conto 12202 con il controllo che il saldo del cc da cui si preleva sia positivo” start transaction; update ContoCorrente set Saldo = Saldo + 10 where NumConto = 12202; update ContoCorrente set Saldo = Saldo – 10 where NumConto = 42177; select Saldo as A from ContoCorrente where NumConto = 42177; if (A>=0) then commit work; else rollback work; Gestione Transazioni 7 Il concetto di transazione Una definizione più precisa di transazione: unità di elaborazione che gode delle proprietà "ACIDE" (ACID): Atomicità Consistenza Isolamento Durabilità (persistenza) Gestione Transazioni 8 ACID: Atomicità Una transazione è una unità atomica (tutto o niente) di elaborazione È fondamentale per garantire l'integrità dei dati Se qualcosa va storto il sistema deve essere in grado di annullare tutti i cambiamenti fatti a partire dall'inizio della transazione La base di dati non può essere lasciata in uno stato intermedio un guasto o un errore prima del commit debbono causare l'annullamento (UNDO) delle operazioni svolte un guasto o errore dopo il commit non deve avere conseguenze Esito Commit = caso "normale" e più frequente Abort (o rollback) richiesto dall'applicazione = suicidio richiesto dal sistema (violazione dei vincoli, concorrenza, incertezza in caso di fallimento) = omicidio Gestione Transazioni 9 ACID: Consistenza La transazione rispetta i vincoli di integrità Conseguenza: se lo stato iniziale è corretto anche lo stato finale è corretto Gestione Transazioni 10 ACID: Isolamento La transazione non risente degli effetti delle altre transazioni concorrenti l'esecuzione concorrente di una collezione di transazioni deve produrre un risultato che si potrebbe ottenere con una esecuzione sequenziale Conseguenza: una transazione non espone i suoi stati intermedi Gestione Transazioni 11 ACID: Durabilità (Persistenza) Gli effetti di una transazione andata in commit non vanno perduti ("durano per sempre"), anche in presenza di guasti Commit significa impegno Gestione Transazioni 12 Controllo di concorrenza Se la proprietà di isolamento non è completamente soddisfatta, due (o più) transazioni effettuate su un database consistente possono portare il database in uno stato inconsistente Due azioni sullo stesso oggetto si dicono essere in confitto se almeno una delle due è una operazione di scrittura Date due transazioni T1 e T2 in conflitto, si possono verificare tre tipologie di situazioni anomale conflitto Write-Read (W-R): T2 legge un dato precedentemente scritto da T1 conflitto Read-Write (R-W): T2 scrive un dato precedentemente letto da T1 conflitto Write-Write (W-W): T2 scrive un dato precedentemente scritto da T1 Gestione Transazioni 13 Conflitti WR: Reading uncommitted data Si può verificare una anomalia se una transazione T2 legge un dato che è stato modificato da una transazione T1 non ancora conclusa (quindi uncommitted) In particolare questa situazione può generare letture sporche Gestione Transazioni 14 Lettura sporca t1 traferisce 100€ da A a B t2 incrementa sia A che B del 6% N.B. Assumiamo sempre un begin of transaction (BOT) come prima operazione di ogni transazione Gestione Transazioni 15 Lettura sporca supponiamo che sia A che B all'inizio valgano 1000: con una esecuzione seriale t1 t2 t1 t2 tempo r1(A) A = A - 100 w1(A) r1(B) B = B + 100 w1(B) commit A = 900*1.06 = 954 B = 1100*1.06 = 1166 A+B=2120 r2(A) A = A * 1.06 w2(A) r2(B) B = B * 1.06 w2(B) commit Gestione Transazioni 16 Lettura sporca supponiamo che sia A che B all'inizio valgano 1000: con una esecuzione seriale t2 t1 t1 t2 tempo r2(A) A = A * 1.06 w2(A) r2(B) B = B * 1.06 w2(B) commit r1(A) A = A - 100 w1(A) r1(B) B = B + 100 w1(B) commit • A = 960 • B = 1160 • A+B = 2120 Gestione Transazioni 17 Lettura sporca supponiamo che sia A che B all'inizio valgano 1000: con esecuzione concorrente di t2 t1 t1 tempo r1(A) A = A - 100 w1(A) t2 r2(A) A = A * 1.06 w2(A) r2(B) B = B * 1.06 w2(B) commit r1(B) B = B + 100 w1(B) commit t2 ha letto uno stato intermedio ("sporco") A = 954 B = 1160 NB: alla fine qualcuno ci ha perso ... e il totale cambia: chi ha guadagnato? Gestione Transazioni 18 Conflitti RW: Unrepeatable read Si possono verificare diverse anomalie se una transazione T2 cambia il valore di un dato che è stato letto da una transazione T1 mentre T1 è ancora in esecuzione In particolare, questa situazione può generare: perdita di aggiornamento, lettura inconsistente (unrepeatable read) Gestione Transazioni 19 Letture inconsistenti t1 legge due volte x: t1 t2 tempo r1(x) r2(x) x=x+1 w2(x) commit r1(x) commit t1 legge due valori diversi per x ! Gestione Transazioni 20 Perdita di aggiornamento Due transazioni identiche: t 1: r(x), x = x + 1, w(x) t2 : r(x), x = x + 1, w(x) Inizialmente x=2; dopo una esecuzione seriale x=4 Una esecuzione concorrente: tempo t1 t2 r1(x) x=x+1 r2(x) x=x+1 w1(x) commit w2(x) commit Un aggiornamento viene perso: x = 3 Gestione Transazioni 21 Conflitti WW: Overwriting uncommitted data Si possono verificare anomalie se una transazione T2 sovrascrive il valore di un dato che è già stato modificato da una transazione T1, mentre T1 è ancora in esecuzione questa situazione può generare effetti fantasma Gestione Transazioni 22 Effetti fantasma vincolo: x+y+z=1000 t1 t2 sum = 0 read(x) sum = sum + x tempo read(y) y = y - 100 write(y) T1 calcola in maniera errata la somma di x, y, z read(y) sum = sum + y read(z) sum = sum + z commit (supponiamo T2 stia spostando soldi dal conto y al conto z: il totale di cassa non cambia … per T1 invece si!) read(z) z = z + 100 write(z) commit Gestione Transazioni 23 Gestione di transazioni mediante lock I DBMS per evitare anomalie nelle transazione concorrenti usano diverse tecniche Una delle più comuni è basata su lock Il lock è un meccanismo che blocca l'accesso ai dati ai quali una transazione accede ad altre transazioni lock a livello di riga, tabella, database lock in operazioni di scrittura/lettura Quando una risorsa è bloccata, le transazioni che ne richiedono l'accesso vengono messe in coda quindi devono aspettare (che il lock sia rimosso) In sostanza, questo è un meccanismo efficace, ma influisce sulle prestazioni Gestione Transazioni 24 Livelli di isolamento Idealmente vorremmo avere sempre garantita la proprietà di isolamento delle transazioni Ma questa proprietà ha dei costi che possono limitare le prestazioni del sistema I DBMS offrono diversi livelli di isolamento: maggiori restrizioni, minori prestazioni Il programmatore deve conoscere i livelli di isolamento e scegliere quello sufficiente ai propri obiettivi Gestione Transazioni 25 Livelli di isolamento SQL SERIALIZABLE assicura che la transazione T legge solo cambiamenti fatti da transazioni concluse nessun valore letto o scritto da T verrà cambiato da altre transazione finché T non è conclusa se T legge un insieme di valori acceduti secondo qualche condizione di ricerca, l'insieme non viene modificato da altre transazione finché T non è conclusa REPEATABLE READ assicura che la transazione T legge solo cambiamenti fatti da transazioni concluse nessun valore letto o scritto da T verrà cambiato da altre transazione finché T non è conclusa READ COMMITTED assicura che la transazione T legge solo cambiamenti fatti da transazioni concluse T non vede nessun cambiamento eventualmente effettuato da transazioni concorrenti non concluse tra i valori letti all'inizio di T READ UNCOMMITTED a questo livello di isolamento una transazione T può leggere modifiche fatte ad un oggetto da un transazione in esecuzione; ovviamente l'oggetto può essere cambiato mentre T è in esecuzione. Quindi T è soggetta a effetti fantasma Gestione Transazioni 26 Livelli di isolamento SQL Il livello di isolamento può essere scelto per ogni transazione read uncommitted permette letture sporche, letture inconsistenti, aggiornamenti fantasma e inserimenti fantasma read committed evita letture sporche ma permette letture inconsistenti, aggiornamenti fantasma e inserimenti fantasma repeatable read evita tutte le anomalie esclusi gli inserimenti fantasma serializable evita tutte le anomalie Nota: la perdita di aggiornamento è sempre evitata Inoltre le transazioni possono essere definite read-only Gestione Transazioni 27 Livelli di isolamento e anomalie livello di isolamento lettura sporca lettura inconsistente effetto fantasma READ UNCOMMITTED può verificarsi può verificarsi può verificarsi READ COMMITTED NO può verificarsi può verificarsi REPEATABLE READ NO NO può verificarsi SERIALIZABLE NO NO NO Gestione Transazioni 28 Transazioni in SQL START TRANSACTION SET TRANSACTION ISOLATION LEVEL livello istruzioni SQL COMMIT Gestione Transazioni 29 Transazioni in JDBC Scelta della modalità delle transazioni: un metodo definito nell'interfaccia Connection: setAutoCommit(boolean autoCommit) connection.setAutoCommit(true) (default) "autocommit ": ogni operazione è una transazione connection.setAutoCommit(false) gestione delle transazioni da programma connection.commit() connection.rollback() N.B. non c'è start transaction Gestione Transazioni 30 JDBC e livelli di isolamento Il metodo setTransactionIsolation() permette di modificare il livello di isolamento delle transazioni Riceve un parametro intero che può assumere uno dei valori costanti definiti nella interfaccia Connection TRANSACTION_NONE: le transazioni non vengono supportate. Passare questo parametro a setTransactionIsolation() è equivalente ad una chiamata al metodo setAutoCommit(true) TRANSACTION_READ_UNCOMMITTED: nessun livello di isolamento è garantito, quindi possono presentarsi tutte le anomalie Gestione Transazioni 31 JDBC e livelli di isolamento TRANSACTION_READ_COMMITTED: vengono prevenute solo le letture sporche. Le altre anomalie possono ancora presentarsi TRANSACTION_REPEATABLE_READ: possono presentarsi solo inserimenti fantasma TRANSACTION_SERIALIZABLE: è il massimo livello di isolamento. Nessuna anomalia può presentarsi Gestione Transazioni 32 Esempio transazioni con JDBC public public void void evadiOrdine evadiOrdine (int (int codProdotto, codProdotto, String String idOrdine, idOrdine, int int qnt, qnt, Connection Connection con) con) throws throws PersistenceException PersistenceException { { try { try { con.setAutoCommit(false); con.setAutoCommit(false); con.setTransactionLevel(Connection.TRANSACTION_REPEATABLE_READ); con.setTransactionLevel(Connection.TRANSACTION_REPEATABLE_READ); PreparedStatement updateProd updateProd = PreparedStatement = con.prepareStatement("UPDATE con.prepareStatement("UPDATE prodotti prodotti SET quantita=(quantita SET quantita=(quantita - ?) ?) WHERE WHERE codiceProdotto codiceProdotto = = ? ? "); "); updateProd.setInt(1, codProdotto); updateProd.setInt(1, codProdotto); updateProd.setInt(2, qnt); updateProd.setInt(2, qnt); PreparedStatement updateOrd = PreparedStatement updateOrd = con.prepareStatement("UPDATE ordini SET ordini stato = 'evaso' con.prepareStatement("UPDATE SET stato where = 'evaso' idOrdine=?"); where idOrdine=?"); updateOrd.setInt(1, idOrdine); idOrdine); updateOrd.setInt(1, int nProd = prepareProd.executeUpdate(); int nProd = prepareProd.executeUpdate(); int nOrd = prepareOrd.executeUpdate(); int nOrd = prepareOrd.executeUpdate(); if (nProd+nOrd != 2) if (nProd+nOrd != 2) con.rollback(); con.rollback(); else else con.commit(); con.commit(); } catch (SQLException ex) { try { } catch (SQLException ex) { con.rollback(); try { throw new PersistenceException("Transaction failed: " + con.rollback(); ex.getMessage()); throw (SQLException new PersistenceException("Transaction failed: " + ex.getMessage()); } catch sqx) { } catch (SQLException sqx) { throw new PersistenceException("Rollback failed: " + sqx.getMessage()); throw new PersistenceException("Rollback failed: " + sqx.getMessage()); } } } } } } Gestione Transazioni 33 JDBC e livelli di isolamento Attenzione: non tutti i DBMS supportano le transazioni e non tutti quelli che le supportano permettono l'impostazioni di tutti i livelli di isolamento previsti da JDBC È compito del programmatore che usa l'API JDBC verificare le effettive capacità del DBMS in uso A tal fine l'interfaccia Connection mette a disposizione il metodo getMetaData(), che restituisce un oggetto DatabaseMetaData Gestione Transazioni 34 JDBC e livelli di isolamento L'interfaccia DatabaseMetaData offre metodi per reperire informazioni sul DBMS In particolare, per verificare il supporto alle transazioni, abbiamo i metodi: supportsTransactions(): restituisce true se le transazioni sono supportate dal database, false se non lo sono. In questo ultimo caso, il metodo commit() non esegue alcuna operazione e il livello di isolamento è sempre TRANSACTION_NONE supportsTransactionIsolationLevel(int): permette di sapere se il DBMS supporta il livello di isolamento passato come parametro (secondo le costanti definite dall'interfaccia Connection nella slide precedente) Gestione Transazioni 35 JDBC e livelli di isolamento import java.sql.*; public class TransactionCapabilities { public static void main(String[] args) throws SQLException { try { Class.forName("COM.ibm.db2.jdbc.app.DB2Driver"); } catch(ClassNotFoundException e) { System.err.println("Driver non trovato"); } String url = "jdbc:db2:tw_stud"; Connection con = null; try { con = DriverManager.getConnection(url, “******", “******"); }catch(SQLException e){ System.err.println("Connessione non restituita"); } try { DatabaseMetaData dbMetaData = con.getMetaData(); if (dbMetaData.supportsTransactions()) System.out.println("tranzazioni supportate"); if (dbMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)) System.out.println("TRANSACTION_READ_UNCOMMITTED"); if (dbMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)) System.out.println("TRANSACTION_READ_COMMITTED"); if (dbMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)) System.out.println("TRANSACTION_REPEATABLE_READ"); if (dbMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)) System.out.println("TRANSACTION_SERIALIZABLE"); } catch(SQLException e){ System.err.println("Errori lettura metadati"); } finally { con.close(); } } } Gestione Transazioni 36 Limiti di JDBC JDBC rappresenta una buona soluzione per la gestione di transazioni che manipolano un unico DB, ovvero che coinvolgono una unica Connection! In sistemi che manipolano dati appartenenti a diversi DB, ogni unità di lavoro richiede l’accesso a più di una risorsa in questi casi non è possibile garantire la propietà ACID di atomicità con JDBC! Occorre un transaction manager in grado di gestire diverse sorgenti dati (DB) in un unico sistema transazionale Gestione Transazioni 37 Java Transaction API (JTA) Java Transaction API (JTA) fornisce un servizio per la gestione di transazioni distribuite per la piattaforma J2EE Una transazione distribuita coinvolge un transaction manger e uno o più resource manger (ovvero qualunque tipo di datastore persistente) Il transaction manger è responsabile del coordinamento di tutti i partecipanti alla transazione Gestione Transazioni 38 JTA JTA permette l’interazione con lo sviluppatore mediante l’interfaccia javax.transaction.UserTransaction e i metodi begin(), commit() e rollback() Starting a transaction with JTA: Example import javax.transaction.*; import javax.naming.*; // ... UserTransaction utx = (UserTransaction) new InitialContext() .lookup("java:comp/UserTransaction"); utx.begin(); // ... DataSource ds = obtainXADataSource(); Connection conn = ds.getConnection(); pstmt = conn.prepareStatement("UPDATE MOVIES ..."); pstmt.setString(1, "Spinal Tap"); pstmt.executeUpdate(); // ... utx.commit(); // ... Gestione Transazioni 39 Transazioni e Hibernate Come visto nelle precedenti lezioni, Hibernate astrae dalle API JDBC/JTA sottostanti livello di applicazione può essere trasparente a questi dettagli Hibernate espone l’interfaccia org.hibernate.Transaction che permette di lavorare “on top” a JDBC e JTA Rappresenta la demarcazione unificata delle transazioni Compatibile sia a JDBC che a JTA Il maggior beneficio di Hibernate rispetto a JDBC e JTA è di permettere stretta integrazione con il contesto di persistenza Es. flush automatico di Session al commit Gestione Transazioni 40 Transazioni e Hibernate: Esempio import java.util.*; import org.hibernate.*; import persistence.HibernateUtil; //... //First unit of work Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); User user = new User("pippo"); String userId = (String) session.save(user); tx.commit(); session.close(); //... Gestione Transazioni 41 Hibernate Come già sappiamo, l’interfaccia principale di Hibernate è Session All'apertura di un nuovo oggetto della classe Session metodo openSession()della classe SessionFactory viene creata una nuova connessione JDBC con la base di dati di default, Hibernate imposta l'autocommit a false ; dunque comincia a tutti gli effetti una transazione JDBC Gestione Transazioni 42 Hibernate Una Session Hibernate si dice essere “pigra”; questo è un punto a favore di Hibernate La Session non consuma alcuna risorsa fino a che le stesse non sono strettamente necessarie Solo all’inizio di una transazione viene resa disponibile una Connection dal pool di connessioni La chiamata beginTransaction() si traduce in setAutoCommit(false) nella Connection JDBC corrispondente Gestione Transazioni 43 Hibernate Il blocco di statement SQL di una transazione sono eseguiti seguendo la regola “il più tardi possibile” (write-behind ), ovvero al flushing del contesto di persistenza della Session Ciò accade di default al commit() di Transaction Dopo il commit (o il roll-back) della transazione la connessione è rilasciata e “unbound” dalla Session L’inizio di una nuova transazione con la stessa Session necessita di una nuova connessione dal pool di connessioni disponibili Gestione Transazioni 44 Locking ottimistico di sessione In caso di accesso concorrente, affinché non occorrano anomalie di tipo lost-update, Hibernate prevede la possibilità di abilitare un meccanismo di locking ottimistico tale che nel momento in cui viene invocato il flushing, verifica se la porzione della base di dati che sarà modificata non sia cambiata se è cambiata lancia una eccezione StaleObjectStateException Per abilitare il locking ottimistico, nell'elemento class del file di mapping relativo alla classe su cui verte la modifica, è necessario definire l'attributo optimistic-lock pari a all Gestione Transazioni 45 Long-lived transactions Tra il momento in cui si leggono i dati dal DB ed il momento in cui eventuali modiche si rendono persistenti può trascorrere molto tempo Hibernate applica il pattern session-per-conversation: è necessario disabilitare il flushing automatico chiamando il metodo setFlushMode(FlushMode.MANUAL) quando la sessione è aperta l'isolamento è garantito in quanto, abilitando il locking ottimistico, le modiche fatte in transazioni concorrenti sono riconosciute l'atomicità è garantita dal fatto che il flushing viene eseguito solo al termine della transazione, e se la sessione viene chiusa senza fare il flushing, la transazione viene abortita Gestione Transazioni 46 Controllo ottimistico di concorrenza Per la gestione efficiente di accessi concorrenti Hibernate sfrutta la tecnica Optimistic Concurrency Control (OCC) OCC si basa sull’assunzione che la maggior parte delle transazioni verso DB non sono in conflitto con altre transazioni; questo permette di essere piuttosto “permissivi” nel rilasciare la possibilità di esecuzione Se i conflitti sono rari, post-validazioni possono essere svolte efficientemente => alto throughput OCC sfrutta versioning dei dati per ottenere elevati gradi di concorrenza e alta scalabilità Version checking sfrutta numeri di versione o timestamp per fare la detection di aggiornamenti che possono determinare conflitti Gestione Transazioni 47 Riferimenti JDBC API: http://java.sun.com/j2se/1.5.0/docs/api/ index.html Hibernate API: http://docs.jboss.org/hibernate/core/ 3.5/api/ Atzeni, Ceri, Fraternali, Paraboschi, Torlone “Basi di dati – Architetture e linee di evoluzione”, McGraw-Hill Italia, 2009 Christian Bauer and Gavin King. “Java Persistence with Hibernate”, Manning Gestione Transazioni 48
Documenti analoghi
Basi di dati e Web introduzione
Inizia con un begin transaction.
Termina con un end transaction.
La sua esecuzione comporta il raggiungimento di un commit o di un
rollback work e dopo il commit/rollback non si eseguono
altri acce...
Le transazioni
operazioni non sono visibili al mondo esterno.
Dopo l’eventuale commit, le operazioni effettuate sono
Tecnologia di un Database Server - Dipartimento di Matematica e
• begin (o start) transaction (bot) e end transaction (eot)
Il comando end transaction è di norma implicito. Se viene omesso il
comando begin/start transaction, il sistema assume che ogni singola
...
transazioni distribuite - Dipartimento di Ingegneria dell`Informazione
Una transazione è una unità elementare di lavoro svolta da una
applicazione; comandi di transazione:
– Start transaction / end transaction
– Commit / Rollback