Бесконечная тупиковая ситуация на mySQL innoDB - PullRequest
0 голосов
/ 25 февраля 2020

Вот проблема, с которой я недавно столкнулся в моей MySQLdb 5.7 (с механизмом innoDB), размещенной на виртуальной машине в моей учетной записи Google Cloud Platform. Внезапно моя БД пришла в состояние, когда каждая транзакция (такая как логины) в указанной таблице c с именем 'users' завершилась неудачно (бесконечный тайм-аут). Я взял эту ошибку: pymysql.err.OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction'

Ну, в основном, я пытаюсь выяснить, есть ли автоматическое восстановление из этой обведенной ситуации. На сайте MySQL я прочитал, что по умолчанию выполняется откат до последней транзакции, но почему в моей ситуации этого не произошло? После того, как я долго оставался в этой ситуации, мне пришлось перезапустить сервер MySQL.

Мне нужны некоторые инструкции о том, как его исследовать или предпринять действия, чтобы не столкнуться с ним снова, потому что это живая база данных с клиентами.

Ответы [ 2 ]

0 голосов
/ 26 февраля 2020

Ниже приведена хранимая процедура для входа в систему, в которой мы обнаруживаем бесконечный тупик.

CREATE DEFINER=`root`@`%` PROCEDURE `login`(
    in email1 varchar(45), 
    in password1 varchar(256),
    in lastlogin datetime, 
    out s INT(1)
    )
    BEGIN
    DECLARE p INT(11);
    DECLARE counter TINYINT;

      IF EXISTS (select * from user where user.email = email1 AND user.password = password1 AND user.locked = 0 AND user.inactive = 0) THEN
          SELECT id INTO p FROM user WHERE user.email = email1;
          SELECT user.id, user.id_user_roles, user.id_user_settings, user.first_name, user.last_name, UserRoles.description
          FROM user
          LEFT JOIN UserRoles
          ON user.id_user_roles = UserRoles.id_user_roles WHERE user.id = p;
          UPDATE user SET last_login = lastlogin WHERE user.id = p;
          INSERT INTO login_info (id_user, timestamp)
          VALUES (p, lastlogin);
          SET s = 1; 
      ELSE
          SELECT login_error_times INTO counter FROM user WHERE email = email1;
          IF (counter < 3) THEN
             SET counter = counter + 1;
             UPDATE user
             SET login_error_times = counter
             WHERE user.email = email1;
             SET s = 0; 
          ELSE
             UPDATE user
             SET locked = 1
             WHERE user.email = email1;
             SET s = 2;
          END IF;   
      END IF;
    END
0 голосов
/ 26 февраля 2020
InnoDB Engine

* * поддерживает спортивную блокировку на уровне строк, которая может привести к взаимным блокировкам, даже если ваш код вставляет или обновляет одну строку (особенно, если в обновляемой таблице несколько индексов). Лучше всего разработать соответствующий код, чтобы повторить транзакцию, если она не удалась из-за тупика. Некоторая полезная информация о MySQL диагностике тупиков и возможных обходных путях доступна в MySQL Официальной документации

...