E-commerce: acquisto contemporaneo di un articolo

Salve, ho letto su alcuni post come questo

 http://www.phpnews.it/forum/programmazione-php/carrello/msg14477/#msg14477

che esiste il problema di ritrovarsi con un prodotto che ha la stessa giacenza della richiesta di due clienti che vogliono acquistarlo nello stesso momento. Tuttavia anche leggendo il post, mi ritrovo con qualche dubbio ancora in quanto non ho capito funzioni come begin e look che non ho usato.

Nella pagina che ho creato dove c'è il pulsante CONFERMA ,se il cliente clicca, viene eseguito lo script per il controllo della disponibilità, se è tutto ok, l'ordine viene inserito nel database e vengono scalati i prodotti acquistati.

Ora, la mia domanda è questa: Se questa operazione viene eseguita contemporaneamente da due clienti, c'è il pericolo che entrambi riescano a inviarmi l'ordine nel database e che però uno dei due mi faccia ritrovare con una giacenza in negativo nel database?

In verità io ho fatto delle prove con due pc a inviare nello stesso tempo(spero)  lo stesso ordine, ma ho constatato che comunque sempre uno riesce a fare l'ordine, l'altro vine avvisato (grazie al controllo della disponibilità )che il prodotto non è più disponibile come giusto che sia e spero che sia sempre così....

Quindi ho pensato che anche se due utenti provano contemporaneamente ad inserire lo stesso ordine comunque lo script viene eseguito uno per volta e quindi rimane in attesa l'altro. E' così o mi sto illudendo io?

inviato 6 anni fa
MGbyte78
X 0 X
Ora, la mia domanda è questa: Se questa operazione viene eseguita contemporaneamente da due clienti, c'è il pericolo che entrambi riescano a inviarmi l'ordine nel database e che però uno dei due mi faccia ritrovare con una giacenza in negativo nel database?

Il pericolo c'è ma è remoto.

Quindi ho pensato che anche se due utenti provano contemporaneamente ad inserire lo stesso ordine comunque lo script viene eseguito uno per volta e quindi rimane in attesa l'altro. E' così o mi sto illudendo io?

Temo tu ti stia illudendo. Con il Php puoi fare più richieste simultanee al database. Il pericolo dunque esiste. Si può aggirare la cosa usando le transazioni. Come ha suggerito Gianni nella discussione da te indicata.

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Ok, allora dovrò usare le transizioni, ma il procedimento è il seguente?

BEGIN;

faccio la insert

scalo le giacenze dei prodotti

COMMIT;

Tutto qui? In questo modo anche se un secondo utente conferma l'ordine nello stesso momento rimane in attesa?

risposto 6 anni fa
MGbyte78
modificato 6 anni fa
X 0 X

Per le transazioni ti rimando alla documentazione ufficiale:

http://dev.mysql.com/doc/refman/5.5/en/commit.html

Con queste altri ordini verranno messi in attesa.

risposto 6 anni fa
Mario Santagiuliana
X 0 X

La cosa strana è che nel post di Gianni e anche nella documentazione ufficiale si usa una sintassi che non mi funziona , ad esempio per iniziare una transizione basterebbe scrivere BEGIN, ma a me ha funzionato solo quando le varie istruzioni venivano messe all'interno di mysql_query(ISTRUZIONE); come spiegato su un sito trovato tramite google.

risposto 6 anni fa
MGbyte78
X 0 X

Scusa non ho capito...

mysql_query è la funzione del php per fare delle query in un database MySql...mi sembra ovvio che si debba usare questa funzione per comunicare con mysql...

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Bè io ho frainteso invece, scusate. Potrebbe anche capitare (per chi non è tanto esperto magari) che leggendo dei post dove si parla di istruzioni come  BEGIN, COMMIT e ROLLBACK senza inserirli all'interno di mysql_query(perchè la cosa è implicita e scontata per voi), possa anche pensare che si usino senza la funzione mysql_query.

Tuttavia la tua risposta mi ha confermato che si usa con questa funzione.

Grazie, ciao.

risposto 6 anni fa
MGbyte78
X 0 X

Nell'esempio del carrello, in cui prima di acquistare un prodotto bisogna controllare la sua disponibilità, bisogna stare attenti a come si legge la disponibilità.

Infatti per le tabelle InnoDB con setup "standard", le SELECT non bloccano il record letto, quindi due transazioni concorrenti potrebbero leggere entrambe una disponibilità sufficiente all'acquisto e poi mandare sotto zero il numero di prodotti disponibili.

Le SELECT di lettura della disponibilità vanno quindi fatte nella modalità "FOR UPDATE":

SELECT num_articoli_in_magazzino FROM magazzino WHERE id_articolo = 123 FOR UPDATE

La prima transazione che accede al magazzino ottiene subito questo numero mentre le altre aspettano che la prima transazione si concluda.

 :bye:

risposto 6 anni fa
Gianni Tomasicchio
modificato 6 anni fa
X 0 X

Ciao Gianni, grazie per questa info importante, scusami vediamo se ho capito:

All'interno della transizione quando faccio la select per vedere la disponibilità del prodotto richiesto devo aggiungere alla mia query solo FOR UPDATE come ho scritto nel mio esempio sotto?

$sql = "Select * from tbprodotti where codice='$codice' FOR UPDATE";

E così?

Un ultima cosa, che vuol dire setup STANDARD?

risposto 6 anni fa
MGbyte78
X 0 X
All'interno della transizione quando faccio la select per vedere la disponibilità del prodotto richiesto devo aggiungere alla mia query solo FOR UPDATE come ho scritto nel mio esempio sotto?

Esatto, per un database innodb, vedi questa documentazione:

http://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Ok, grazie!!

 :bye:

risposto 6 anni fa
MGbyte78
X 0 X
Un ultima cosa, che vuol dire setup STANDARD?

Il comportamento delle SELECT all'interno di una transazione viene determinato dal parametro transaction-isolation:

http://dev.mysql.com/doc/refman/5.5/en/server-options.html#option_mysqld_transaction-isolation

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html

 :bye:

risposto 6 anni fa
Gianni Tomasicchio
X 0 X

Ho capito dunque che non basta usare le transizioni se la tabella è di tipo innoDB con setup standard e quindi bisogna usare il for update. Grazie per le guide ma non ho capito ancora come faccio a vedere se le mie tabelle sono con setup standard.

Dove lo posso vedere? Nel phpmyadmin?

risposto 6 anni fa
MGbyte78
X 0 X

Si anche :)

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Scusa se "rompo", non riesco a capire nel pannello di controllo di phpMyadmin se il setup è standard, dove devo vedere?

risposto 6 anni fa
MGbyte78
X 0 X

Esegui questa query e riporta il risultato:

SELECT @@GLOBAL.tx_isolation, @@tx_isolation;

risposto 6 anni fa
Gianni Tomasicchio
X 0 X

Ho eseguito la query da phpmyadmin e questo è il risultato:

@@GLOBAL.tx_isolation       -            @@tx_isolation 

     REPEATABLE-READ           -          REPEATABLE-READ

risposto 6 anni fa
MGbyte78
X 0 X

Usi il modello predefinito di InnoDB per il livello di isolamento.

Dai link forniti in precedenza alla documentazione puoi capire meglio il suo funzionamento ed eventualmente provare a variare il comportamento  ;)

Ciao

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Volevo solo sapere se da questo risultato si evince che devo usare FOR UPDATE nella select come mi ha detto Gianni.

risposto 6 anni fa
MGbyte78
X 0 X

Direi di si.

Ciao

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Io a questo problema avevo trovato una soluzione con le queri supportate solo da mysqli che supporta le transazioni e mysql no. Il sistema che sto' ultimando per il commercio elettronico, al momento in cui il cliente invia l'ordine, l'ordine viene memorizzato sul db. Questo ordine poi deve essere confermato tramite elefono e fax lasciato al momento in cui viene spedito l'ordine e qui possiamo avere 2 opzioni. 1) L'ordine viene confermato e i prodotti vengono scalati nel momento in cui il venditore riceve la conferma e le parti si mettono d'accordo sulle varie clausole di consegna(trasporto, luogo della consegna, mezzi di pagamento ecc ecc ecc). 2) Nel caso in cui l'ordine non viene confermato entro 10 giorni, l'ordine viene automaticamente revocato. La conferma dell'ordine puo' essere fatta attraverso tutti i canali possibili(telefono, fax, raccomandata, sms almeno cio' che io consiglio). Poi se due soggetti fanno l'ordine in 2 momenti diversi(es uno oggi e l'altro fra una settimana), quello che conferma dopo l'ordine si attacca al tram se la quantita' di un bene non e' disponibile nel numero ordinato!

risposto 2 anni fa
Blaster83
X 0 X
Effettua l'accesso o registrati per rispondere a questa domanda