Come da consiglio aggiungo la parte sulle transazioni vere e proprie.
Riprendo da dove avevo interrotto.
Mentre le operazioni di LOCK possono essere eseguite su qualunque tipo di tabella quelle relative alle TRANSAZIONI devono per forza essere eseguite o su tabelle InnoDB (che consiglio www.innodb.com ) o su BDB (www.sleepycat.com).
MySql gestisce le tabelle InnoDB fin dalla versione 3.23 solo che per questa versione è necessario attivarle mentre per le versioni dalla 4 in poi queste sono già attive di default.
Per le informazioni relative all’ abilitazione delle tabelle InnoDB si rimanda al manuale in linea su www.mysql.com.
Creare una tabella InnoDB è praticamente uguale a creare una qualsiasi altra tabella, bisognerà solo prestare attenzione ad aggiungere l’ attributo InnoDB tra i parametri. La sintassi è la seguente:
CREATE TABLE nome_tabella (dichirazione dei campi) TYPE=InnoDB;
Per esempio la nostra tabella Prodotti sarà così dichiarata:
CREATE TABLE Prodotti (IdProdotto INT, Descrizione TINYTEXT, Qta INT) TYPE=InnoDB;
Ovviamente in un caso reale IdProdotto sarà chiave primaria e probabilmente di tipo auoincrement.
Una tabella può anche essere convertita in InnoDB tramite il comando DROP TABLE .
Adesso passiamo all’ esame delle TRANSAZIONI vere e proprie, come esempio useremo sempre quello della tabella Prodotti.
Per iniziare una transazione è sufficiente digitare il comando BEGIN , però fate attenzione perché se si utilizzano le transazioni tutte le operazioni in scrittura non vengono effettuate automaticamente ma bisogna esplicitamente dire a MySql di effettuarle tramite il comando COMMIT .
Ecco le nostre operazioni sulla tabella Prodotti (due thread A e B, 10 prodotti disponibili, A ne vuole 3 B ne vuole 8) riviste utilizzando le transazioni:
L’ utente A (che come dicevo prima in realtà è un thread) inizia la sua transazione:
BEGIN;
SELECT Qta FROM Prodotti WHERE IdProdotto=123;
….
….
//Altre eventuali operazioni o query
….
….
UPDATE Prodotti SET Qta=Qta-3 WHERE IdProdotto=123;
….
….
//A questo punto A decide di controllare quanti articoli con IdProdotto=123 sono presenti con una select
SELECT Qta FROM Prodotti WHERE IdProdotto=123;
La risposta sarà 7, quindi si potrebbe pensare tutto Ok.
A questo punto anche B vuole fare il suo ordine e fa una select per controllare che la quantità di merce di cui necessita sia disponibile:
SELECT Qta FROM Prodotti WHERE IdProdotto=123;
La risposta sarà 10.
Vi starete domandando come sia possibile visto che stiamo usando le transazioni, la risposta va ricercata nel fatto che A è ancora dentro la sua transazione ed ha aggiornato i dati solamente in locale, non ha ancora scritto i dati sul database.
Se a questo punto B decidesse di fare la seguente update per rendere effettivo il suo ordine:
UPDATE Prodotti SET Qta=Qta-8 WHERE IdProdotto=123 (3)
Questa (B) verrebbe immediatamente sospesa perché il record in questione è bloccato (A sta eseguendo la transazione avviata col comando BEGIN). Il meccanismo di lock sul record si chiama row level locking.
Quindi B deve attendere che il record sia sbloccato e questo avviene quando A invia il comando COMMIT che provoca la scrittura dei dati nel db.
A questo punto B può eseguire la query (3) che era stata messa in standby.
Cosa succede, che se facciamo una select su Qta avremo come risultato di ritorno -1.
Ovviamente in un programma vero avremmo dovuto predisporre delle operazioni dicontrollo sullo stato di Qta, ciò non toglie che una volta fatta questa verifica noisi possa riportare lo stato del database a quello iniziale e questo viene fatto col comando ROLLBACK che non farà altro che annullare le modifiche effettuate da B.
Infatti se ora facciamo:
SELECT Qta FROM Prodotti WHERE IdProdotto=123;
Ci verrà ritornato 7 e non più -1.
In pratica cosa è successo? Che in maniera totalmente trasparente all’ utente l’ ordine A è stato accettato (può essere evaso perché a magazzino c’ è merce sufficiente) mentre l’ordine Bè stato rifiutato, il tutto preservando l’ integrità dei dati.
Spero di essere stato sufficientemente chiaro.
Se trovate errori o inesattezze segnalatele subito che provvederò a correggere.
Ciao a tutti, Mc

Rispondi quotando
