sql >> Databáze >  >> RDS >> Mysql

Jak správně používat transakce a zámky k zajištění integrity databáze?

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í

  1. Zahájit transakci
  2. 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.

  1. 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:

  1. UPDATE ... tabulku v kroku 3, označte položku jako rezervovanou. Proveďte jakýkoli jiný INSERT s a UPDATE potřebujete také.

  2. Zaplatit. Pokud platební služba oznámí, že platba nefungovala, proveďte vrácení.

  3. V případě úspěchu zaznamenejte platbu.

  4. 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í.)



  1. PostgreSQL - jak vykreslit datum v jiném časovém pásmu?

  2. Chyba Oracle ORA-12154 na místní IIS, ale ne na serveru Visual Studio Development Server

  3. Jak LTRIM_ORACLE() funguje v MariaDB

  4. MySQL Workbench nezobrazuje výsledky dotazu