Zatím je to v pořádku, alespoň to zabrání uživateli v provádění pokladny ve více relacích (vícenásobné pokusy o zaplacení stejné karty – dobré, když se vypořádají s dvojitým kliknutím.)
jak to kontrolujete? Se standardním SELECT
nebo pomocí SELECT ... FOR UPDATE
? Na základě kroku 5 předpokládám, že kontrolujete vyhrazený sloupec u položky nebo něco podobného.
Problém je v tom, že SELECT ... FOR UPDATE
v kroku 2 NEPOUŽÍVÁ FOR UPDATE
zámek na všechno ostatní. Platí pouze pro to, co je SELECT
ed:cart-item
stůl. Na základě názvu to bude jiný záznam pro každý košík/uživatele. To znamená, že pokračování ostatních transakcí NEBUDE zablokováno.
Podle výše uvedeného, na základě informací, které jste poskytli, můžete skončit s tím, že si stejnou položku koupí více lidí, pokud nepoužíváte SELECT ... FOR UPDATE
v kroku 3.
Navrhované řešení
- Zahájit transakci
SELECT ... FOR UPDATE
cart-item
stůl.
Tím se zabrání spuštění dvojitého kliknutí. To, co zde vyberete, by měl být nějaký druh sloupce „objednaný košík“. Pokud to uděláte, druhá transakce se zde pozastaví a počká na dokončení první a poté si přečte výsledek, co první uložila do databáze.
Pokud cart-item
, nezapomeňte zde ukončit proces platby tabulka říká, že již bylo objednáno.
SELECT ... FOR UPDATE
tabulku, kde zaznamenáte, zda byla položka rezervována.
Toto uzamkne OSTATNÍ vozíky/uživatele, aby si tyto položky nemohli přečíst.
Na základě výsledku, pokud položky nejsou rezervovány, pokračujte:
-
UPDATE ...
tabulku v kroku 3, označte položku jako rezervovanou. Proveďte jakýkoli jinýINSERT
s aUPDATE
potřebujete také. -
Zaplatit. Pokud platební služba oznámí, že platba nefungovala, proveďte vrácení.
-
V případě úspěchu zaznamenejte platbu.
-
Potvrďte transakci
Ujistěte se, že mezi kroky 5 a 7 neuděláte nic, co by mohlo selhat (např. odesílání e-mailů), jinak můžete skončit tak, že provedou platbu, aniž by to bylo zaznamenáno, v případě, že se transakce vrátí zpět.
Krok 3 je důležitým krokem, pokud jde o zajištění toho, aby se dva (nebo více) lidé nepokoušeli objednat stejnou položku. Pokud to zkusí dva lidé, 2. osoba skončí tak, že jejich webová stránka "zamrzne", zatímco zpracovává první. Poté, když první skončí, druhý přečte sloupec „rezervováno“ a vy můžete uživateli vrátit zprávu, že již někdo danou položku zakoupil.
Platba v transakci nebo ne
To je subjektivní. Obecně platí, že chcete uzavřít transakce co nejrychleji, abyste zabránili přístupu více lidí k databázi najednou.
V tomto případě však skutečně chcete, aby počkali. Jde jen o to, jak dlouho.
Pokud se rozhodnete potvrdit transakci před platbou, budete muset zaznamenat svůj postup do nějaké mezitabulky, provést platbu a poté zaznamenat výsledek. Uvědomte si, že pokud se platba nezdaří, budete muset ručně vrátit záznamy o rezervaci položek, které jste aktualizovali.
VYBRAT... PRO AKTUALIZACI na neexistujících řádcích
Jen malé varování pro případ, že návrh vaší tabulky zahrnuje vkládání řádků tam, kde je potřebujete dříve SELECT ... FOR UPDATE
:Pokud řádek neexistuje, daná transakce NEZPŮSOBÍ, že ostatní transakce budou čekat, pokud také SELECT ... FOR UPDATE
stejný neexistující řádek.
Ujistěte se tedy, že vaše požadavky vždy serializujete pomocí SELECT ... FOR UPDATE
na řádku, o kterém víte, že existuje jako první. Poté můžete SELECT ... FOR UPDATE
na řádku, který ještě může nebo nemusí existovat. (Nesnažte se provést pouze SELECT
na řádku, který může nebo nemusí existovat, protože budete číst stav řádku v době zahájení transakce, nikoli v okamžiku spuštění SELECT
. Takže SELECT ... FOR UPDATE
na neexistujících řádcích je stále něco, co musíte udělat, abyste získali nejaktuálnější informace, jen si uvědomte, že to nezpůsobí čekání dalších transakcí.)