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

Zpracování latence v transakcích MySQL

Nechcete vše zapouzdřit do jednoho velkého dotazu, protože to vlastně také nic nevyřeší, jen to sníží pravděpodobnost.

Co potřebujete, jsou zámky na řádcích nebo zámky na indexu, kam by se vložil nový řádek.

Jak tedy získáme exkluzivní zámky?

Dvě připojení, mysql1 a mysql2, každé z nich vyžaduje exkluzivní zámek pomocí SELECT ... FOR UPDATE . Tabulka 'historie' má sloupec 'user_id', který je indexován. (Je to také cizí klíč.) Nebyly nalezeny žádné řádky, takže se zdá, že oba postupují normálně, jako by se nic neobvyklého nestalo. User_id 2808 je platné, ale nemá nic v historii.

mysql1> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql2> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql1> select * from history where user_id = 2808 for update;
Empty set (0.00 sec)

mysql2> select * from history where user_id = 2808 for update;
Empty set (0.00 sec)

mysql1> insert into history(user_id) values (2808);

... a nedostávám zpět výzvu ... žádná odpověď ... protože další relace má také zámek ... ale pak:

mysql2> insert into history(user_id) values (2808);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Poté mysql1 okamžitě vrátí úspěch na vložení.

Query OK, 1 row affected (3.96 sec)

Zbývá pouze to, aby mysql1 COMMIT a magicky jsme zabránili uživateli s 0 položkami vložit více než 1 položku. Zablokování nastalo, protože obě relace potřebovaly, aby se staly nekompatibilní věci:mysql1 potřeboval mysql2, aby uvolnil svůj zámek, než se bude moci zavázat, a mysql2 potřeboval mysql1, aby uvolnil svůj zámek, než bude moci vložit. Někdo ten boj musí prohrát a obecně vlákno, které udělalo nejméně práce, je poražené.

Ale co když už existoval 1 nebo více řádků, když jsem provedl příkaz SELECT ... FOR UPDATE ? V takovém případě by zámek byl na řádcích, takže při druhé relaci zkuste SELECT by ve skutečnosti zablokovalo čekání na SELECT dokud se první relace nerozhodla buď COMMIT nebo ROLLBACK , kdy by druhá návštěva zaznamenala přesný počet řádků (včetně těch, které byly vloženy nebo odstraněny první návštěvou) a mohla by přesně rozhodnout, že uživatel již má povolené maximum.

Nemůžete překonat rasovou podmínku, ale můžete je uzamknout.




  1. Docker – Spusťte Apache na hostiteli a kontejneru pro různé webové stránky

  2. Jak změnit uživatele na superuživatele v PostgreSQL

  3. Jak replikovat pouze INSERTy, nikoli DELETE/UPDATE na Slony Slave Node?

  4. Připojení k mysql v xampp bez hesla