Ho 2 tabelle per gestire degli acquisti, la loro struttura, a cui ho lasciato solo i campi utili a spiegare cosa mi serve, è la seguente.
codice:
PRODOTTI
-------------------------------------------
| id | nome | quantita | prezzo | venduto |
-------------------------------------------
il campo quantita, quando un prodotto è disponibile, sarà sempre 1, non sono previste quantità superiori
il campo venduto vale 0 finché non si effettua un acquisto, poi diventa 1
ACQUISTI
-------------------------------------------------------
| id | prodotto | acquirente | prezzo | data_acquisto |
-------------------------------------------------------
il campo prodotto referenzia l'id del prodotto
Il problema è questo: la gestione di acquisti concorrenti.
Ho già letto la pillola riguardo a questo aspetto, ma mi ha lasciato dei dubbi avendo letto anche altre cose in giro.
Ho intenzione di eseguire un acquisto faccio così (lo scrivo con mysql perché mi viene più veloce e lo possono capire tutti, per il progetto uso CodeIgniter e ActiveRecords e magari qualcuno non lo conosce e non capisce cosa succede)
Codice PHP:
mysql_query('BEGIN'); //inizio una transazione
$query = "SELECT id FROM prodotto WHERE id=id_del_prodotto AND quantita=1 AND venduto=0";
$result = mysql_query($query);
if ( mysql_num_rows($result) == 1 ) //il prodotto è stato trovato
{
//update del prodotto acquistato
$query = "UPDATE prodotti SET quantita=0, venduto=1 WHERE id=id_del_prodotto";
$result = mysql_query($query);
if ( mysql_affected_rows() == 1 ) //l'update è avvenuto
{
//inserisco l'acquisto nella tabella acquisti
$query = "INSERT INTO acquisti ....";
$result = mysql_query($query);
if ( mysql_affected_rows() == 1 )
{
mysql_query('COMMIT');
return TRUE;
}
else //INSERTfallito
{
mysql_query('ROLLBACK');
return FALSE;
}
}
else //UPDATE fallito
{
mysql_query('ROLLBACK');
return FALSE;
}
}
else //il prodotto non è stato trovato o la quantità non è 1, dunque nel frattempo l'hanno acquistato
{
mysql_query('ROLLBACK');
return FALSE;
}
Bene, inizia una transazione, esegue la SELECT che va a buon fine e si va avanti.
Prima del COMMIT o di un ROLLBACK arriva un altro utente che vuole comprare lo stesso prodotto, quindi anche lui effettua la SELECT.
A questo secondo utente la SELECT andrà a buon fine e andrà avanti anche lui o si attiverà una LOCK sulla riga e quindi la SELECT del secondo resterà in attesa di essere eseguita fino a che la prima transazione non sarà terminata? In questo secondo caso non ci sarebbe alcun problema, ma non so la risposta.
Potrei anche mettere a 1 il campo "venduto" subito dopo la SELECT, ma se la seconda transazione avviene prima che lo faccio comunque ho un problema.
Ad ogni modo anche così facendo, la modifica al campo "venduto" sarebbe all'interno della transazione e il secondo utente non se ne accorgerebbe dato che non è realmente impostato sul DB.
Insomma, mi basta usare una transazione come specificato sopra o devo preoccuparmi di altro?