Så långt så bra, detta kommer åtminstone att förhindra att användaren gör kassan i flera sessioner (flera gånger försöker kassan samma kort - bra att hantera dubbelklick.)
Hur kollar man? Med en standard SELECT
eller med en SELECT ... FOR UPDATE
? Baserat på steg 5 gissar jag att du markerar en reserverad kolumn på objektet, eller något liknande.
Problemet här är att SELECT ... FOR UPDATE
i steg 2 kommer INTE att tillämpa FOR UPDATE
lås till allt annat. Det gäller bara det som är SELECT
ed:cart-item
tabell. Baserat på namnet kommer det att bli en annan post för varje vagn/användare. Detta innebär att andra transaktioner INTE kommer att blockeras från att fortsätta.
Efter ovanstående, baserat på informationen du har angett, kan du sluta med att flera personer köper samma vara, om du inte använder SELECT ... FOR UPDATE
på steg 3.
Föreslagen lösning
- Börja transaktionen
SELECT ... FOR UPDATE
cart-item
tabell.
Detta kommer att låsa ett dubbelklick från att köras. Det du väljer här bör vara någon sorts "vagnbeställd" kolumn. Om du gör detta kommer en andra transaktion att pausa här och vänta på att den första ska slutföras och sedan läsa resultatet vad den första sparade i databasen.
Se till att avsluta utcheckningsprocessen här om cart-item
tabellen säger att den redan har beställts.
SELECT ... FOR UPDATE
tabellen där du registrerar om ett objekt har reserverats.
Detta kommer att låsa ANDRA vagnar/användare från att kunna läsa dessa föremål.
Baserat på resultatet, om objekten inte är reserverade, fortsätt:
-
UPDATE ...
tabellen i steg 3, markera objektet som reserverat. Gör någon annanINSERT
s ochUPDATE
du behöver också. -
Betala. Utfärda en återställning om betaltjänsten säger att betalningen inte fungerade.
-
Registrera betalningen, om den lyckas.
-
Bekräfta transaktion
Se till att du inte gör något som kan misslyckas mellan steg 5 och 7 (som att skicka e-post), annars kan du sluta med att de gör en betalning utan att den registreras, i händelse av att transaktionen återställs.
Steg 3 är det viktiga steget när det gäller att se till att två (eller fler) personer inte försöker beställa samma vara. Om två personer försöker, kommer den andra personen att få sin webbsida att "hänga sig" medan den bearbetar den första. När den första är klar kommer den andra att läsa kolumnen "reserverad" och du kan skicka ett meddelande till användaren om att någon redan har köpt den artikeln.
Betalning i transaktion eller inte
Detta är subjektivt. I allmänhet vill du stänga transaktioner så snabbt som möjligt för att undvika att flera personer låses ute från att interagera med databasen samtidigt.
Men i det här fallet vill du faktiskt att de ska vänta. Det är bara en fråga om hur länge.
Om du väljer att genomföra transaktionen före betalning, måste du registrera dina framsteg i någon mellantabell, köra betalningen och sedan registrera resultatet. Tänk på att om betalningen misslyckas måste du manuellt ångra objektreservationsposterna som du uppdaterade.
VÄLJ ... FÖR UPPDATERING på obefintliga rader
Bara ett ord av varning, ifall din tabelldesign innebär att du infogar rader där du behöver tidigare SELECT ... FOR UPDATE
:Om en rad inte finns kommer den transaktionen INTE att få andra transaktioner att vänta, om de också SELECT ... FOR UPDATE
samma obefintliga rad.
Så se till att alltid serialisera dina förfrågningar genom att göra en SELECT ... FOR UPDATE
på en rad som du vet finns först. Sedan kan du SELECT ... FOR UPDATE
på raden som kanske eller kanske inte finns ännu. (Försök inte att bara göra en SELECT
på raden som kanske finns eller inte finns, eftersom du kommer att läsa radens tillstånd när transaktionen startade, inte i det ögonblick du kör SELECT
. Så, SELECT ... FOR UPDATE
på obefintliga rader är fortfarande något du behöver göra för att få den mest uppdaterade informationen, var bara medveten om att det inte kommer att få andra transaktioner att vänta.)