PHP/MySQL Transactions…
Gennaio 8, 2008 di jp
Ci son cose che proprio non digerisco di SQL, una di quelle è la clausola INSERT e soprattutto come viene gestita in MySQL (via PHP).
Ormai tutti i database di questo mondo permettono di avere tabelle con indici/chiavi numerici autoincrementanti (che non sono standard) eppure la loro implementazione della INSERT spesso viene gestita come una “procedura” e non come una “funzione“: inserisci qualcosa (indice nuovo e autoincrementato) e poi ti tocca fare subito un’altra query (o invocare una funzione wrapper apposita come mysql_insert_id()) per sapere l’ID del record appena inserito (LAST ID).
In una applicazione web seria, con molti inserimenti concorrenti, fra la INSERT e la SELECT (che recupera l’ultimo ID inserito) può inserirsi qualche altra operazione (magari un altro inserimento) che fa cambiare erroneamente il LAST ID…
Una semplice soluzione è rappresentata dalle cosiddette transazioni (secondo SQL e nella documentazione di MySQL).
Si tratta di una serie di query, opportunamente raggruppate, che viene processata “atomicamente” (cfr. lettera “A” delle cosiddette “proprietà ACID” nel campo dei database), ossia come se fosse un’unica operazione.
mysql_query(’START TRANSACTION’);
//Svariate query (INSERT, RECUPERO ULTIMO ID INSERITO, UPDATE, …)
// [...]
//Verifica prima della chiusura
if($TUTTO_OK)
{
// confermiamo l’intera transazione
mysql_query(’COMMIT’);
}
else
{
// annulliamo l’intera transazione
mysql_query(’ROLLBACK’);
}
Il procedimento è semplice:
- si apre la transazione;
- vengono scritte le query da eseguire “in blocco”
- si conferma l’intero blocco e le relative operazione (COMMIT) o si annullano (ROLLBACK)
Non si sa nulla circa possibili ottimizzazioni a livello di “blocco di query” anche se è possibile che l’ottimizzatore di query interno a MySQL riesca a operare in maniera più agevole e con una migliore granularità (un conto è ottimizzare n query in un colpo, un colpo è invece dover fare n ottimizzazioni su una query per volta).


Scusa JP ma qui ti becchi una bastonata…
Non e’ un problema di MySQL/PHP: e’ un problema di tutte le applicazioni con scritture concorrenti e nessun motore di DB/interfaccia e’ in grado di risolverti la questione automagically (a meno che la funzione di inserimento del frontend non faccia una lock senza dirtelo e ti ritorni l’ID inserito tramite una chiamata in sequenza alla funzione di recpuero dell’ID).
I lock sulle tabelle ed i blocchi di query servono proprio a questo!
Nel post non ho mai definito “problema” quanto esposto.
Semplicemente, visto che ogni implementazione (es: la citata “MySQL su PHP”
si crea o “personalizza” a piacere le cose andando fuori standard (funzioni, clausole, … ne ho viste di ogni), non vedrei nulla di male se estendesse _anche_ la INSERT per far tornare qualcosa _direttamente_ e senza giri malsani che forzano a usare lock, transaction o quant’altro.
Da quello che mi ha detto Eros (che si è letto i libroni dello standard SQL) non esiste il concetto di tipo autoincrementante in SQL e quindi questa tipologia di datatype è una estensione (ormai adottata universalmente o quasi) => estendono SQL per supportare sta cosa e non estendono LA funzione che la usa? Ma dai…
Il senso del post era: come si fa a ottenere il LAST ID in maniera “sicura”.
PS: grazie per il commento. ^^
Ehm… ok, non capisco perche’ ti sei concentrato su PHP/MySQL, allora.
Sembrava che stessi descrivendo un problema unico di tale accoppiata!
Veramente ho parlato di “implementazioni di DB” e ho citato l’esempio MySQL/PHP visto che è quello con cui mi son trovato a “giocare” recentemente…
Io ho riletto, ma da come ha disposto le frasi continuo a fraintendere! ^^
Vabbe’, tanto ormai ci siamo capiti.
Beh… Spesso mi fraintendo da solo, quando penso fra me e me (”fraintendimento interiore”), quindi non preoccuparti: è (solo) colpa mia.
Ghghgh…