Mysql
 sql >> база данни >  >> RDS >> Mysql

Обработка на латентност в MySQL транзакции

Не сте обвързани с това, че не искате да капсулирате всичко в една голяма заявка, защото това всъщност също няма да реши нищо, а само прави по-малко вероятно.

Това, от което се нуждаете, са ключалки на редовете или ключалки на индекса, където ще бъде вмъкнат новият ред.

И така, как да получим изключителни ключалки?

Две връзки, mysql1 и mysql2, всяка от които изисква ексклузивно заключване с помощта на SELECT ... FOR UPDATE . Таблицата 'history' има колона 'user_id', която е индексирана. (Това също е външен ключ.) Няма открити редове, така че изглежда, че и двата работят нормално, сякаш нищо необичайно няма да се случи. User_id 2808 е валиден, но няма нищо в историята.

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);

... и не получавам подканата си обратно ... няма отговор ... защото друга сесия също има заключване ... но след това:

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

Тогава mysql1 незабавно връща успех на вмъкването.

Query OK, 1 row affected (3.96 sec)

Всичко, което остава, е mysql1 да COMMIT и магически предотвратихме потребител с 0 записа да вмъкне повече от 1 запис. Безизходицата възникна, защото и двете сесии се нуждаеха от несъвместими неща, за да се случат:mysql1 се нуждаеше от mysql2, за да освободи заключването си, преди да може да извърши ангажимент, а mysql2 имаше нужда от mysql1, за да освободи заключването си, преди да може да вмъкне. Някой трябва да загуби тази битка и като цяло нишката, която е свършила най-малко работа, е губеща.

Но какво ще стане, ако вече имаше 1 или повече реда, когато направих SELECT ... FOR UPDATE ? В този случай заключването щеше да е на редовете, така че втората сесия да се опита да SELECT всъщност би блокирал чакането на SELECT докато първата сесия реши или да COMMIT или ROLLBACK , в който момент втората сесия щеше да види точно преброяване на броя на редовете (включително всички вмъкнати или изтрити от първата сесия) и можеше точно да реши, че потребителят вече има максимално разрешения.

Не можете да надминете условията на състезанието, но можете да ги заключите.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да получа първичен ключ на таблицата?

  2. Python Pandas записват в sql с NaN стойности

  3. Как да извлека данни от 2 таблици?

  4. Импортирайте голям csv файл в mysql база данни с помощта на php

  5. конвертирайте mysql резултата в json с правилни типове