Mysql
 sql >> Database >  >> RDS >> Mysql

Come utilizzare correttamente le transazioni e i blocchi per garantire l'integrità del database?

Fin qui tutto bene, questo impedirà almeno all'utente di effettuare il checkout in più sessioni (più volte tentando di effettuare il checkout della stessa carta - buono per gestire i doppi clic.)

Come controlli? Con un SELECT standard o con un SELECT ... FOR UPDATE ? In base al passaggio 5, immagino tu stia controllando una colonna riservata sull'articolo o qualcosa di simile.

Il problema qui è che SELECT ... FOR UPDATE nel passaggio 2 NON applicherà il FOR UPDATE blocca tutto il resto. Si applica solo a ciò che è SELECT ed:il cart-item tavolo. In base al nome, sarà un record diverso per ogni carrello/utente. Ciò significa che le altre transazioni NON verranno bloccate.

Seguendo quanto sopra, in base alle informazioni che hai fornito, potresti finire con più persone che acquistano lo stesso articolo, se non stai utilizzando SELECT ... FOR UPDATE al passaggio 3.

Soluzione consigliata

  1. Inizia transazione
  2. SELECT ... FOR UPDATE l'cart-item tabella.

Questo bloccherà un doppio clic dall'esecuzione. Quello che selezioni qui dovrebbe essere una sorta di colonna "carrello ordinato". Se lo fai, una seconda transazione si fermerà qui e attenderà che la prima finisca, quindi leggerà il risultato che la prima ha salvato nel database.

Assicurati di terminare la procedura di pagamento qui se il cart-item la tabella dice che è già stato ordinato.

  1. SELECT ... FOR UPDATE la tabella in cui registri se un articolo è stato prenotato.

Ciò impedirà ad ALTRI carrelli/utenti di leggere quegli articoli.

In base al risultato, se gli articoli non sono prenotati, continua:

  1. UPDATE ... la tabella al punto 3, contrassegnando l'articolo come riservato. Esegui qualsiasi altro INSERT se UPDATE anche tu hai bisogno.

  2. Fare un pagamento. Emetti un rollback se il servizio di pagamento afferma che il pagamento non ha funzionato.

  3. Registra il pagamento, in caso di successo.

  4. Impegna transazione

Assicurati di non fare nulla che potrebbe non riuscire tra i passaggi 5 e 7 (come l'invio di e-mail), altrimenti potresti finire con loro di effettuare un pagamento senza che venga registrato, nel caso in cui la transazione venga annullata.

Il passaggio 3 è il passaggio importante per assicurarsi che due (o più) persone non provino a ordinare lo stesso articolo. Se due persone ci provano, la seconda persona finirà per avere la propria pagina web "bloccata" mentre elabora la prima. Quindi, al termine della prima, la seconda leggerà la colonna "riservato" e potrai restituire un messaggio all'utente che qualcuno ha già acquistato quell'articolo.

Pagamento in transazione o meno

Questo è soggettivo. In genere, desideri chiudere le transazioni il più rapidamente possibile, per evitare che più persone vengano bloccate dall'interazione con il database contemporaneamente.

Tuttavia, in questo caso, in realtà vuoi che aspettino. È solo questione di quanto tempo.

Se scegli di confermare la transazione prima del pagamento, dovrai registrare i tuoi progressi in una tabella intermedia, eseguire il pagamento e quindi registrare il risultato. Tieni presente che se il pagamento non riesce, dovrai annullare manualmente i record di prenotazione dell'articolo che hai aggiornato.

SELEZIONARE ... PER AGGIORNAMENTO su righe inesistenti

Solo una parola di avvertimento, nel caso in cui la progettazione della tabella comporti l'inserimento di righe in cui è necessario SELECT ... FOR UPDATE :Se una riga non esiste, quella transazione NON causerà l'attesa di altre transazioni, se anche SELECT ... FOR UPDATE la stessa riga inesistente.

Quindi, assicurati di serializzare sempre le tue richieste eseguendo un SELECT ... FOR UPDATE su una riga che sai esiste per prima. Quindi puoi SELECT ... FOR UPDATE sulla riga che può o non può esistere ancora. (Non provare a fare solo un SELECT sulla riga che può esistere o meno, poiché leggerai lo stato della riga nel momento in cui è iniziata la transazione, non nel momento in cui esegui il SELECT . Quindi, SELECT ... FOR UPDATE su righe inesistenti è ancora qualcosa che devi fare per ottenere le informazioni più aggiornate, tieni presente che non causerà l'attesa di altre transazioni.)