DeadD блокировка MariaDB при обновлении строки с использованием первичного ключа - PullRequest
0 голосов
/ 21 декабря 2018

Получение тупиковой ситуации в MariaDB (10.1) при обновлении последнего действия пользователя в таблице.

Запрос, вызывающий ошибку:

UPDATE auth_sessions SET last_activity_time='2018-12-21 05:45:39 WHERE id= 481;

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

Ниже приведен статус, полученный от show engine innodb status ;

------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-12-21 05:45:39 7fe5b8e6eb00
*** (1) TRANSACTION:
TRANSACTION 3742528, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 12 lock struct(s), heap size 2936, 81 row lock(s)
MySQL thread id 1941, OS thread handle 0x7fe5b5df4b00, query id 43106 localhost 127.0.0.1 root updating
UPDATE auth_sessions
                                                    SET last_activity_time= NAME_CONST('time_now',_latin1'2018-12-21 05:45:39' COLLATE 'latin1_swedish_ci')
                                                    WHERE id= NAME_CONST('temp_session_id',481)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 470949 page no 6 n bits 160 index `PRIMARY` of table `xfusion_auth_engine`.`auth_sessions` trx table locks 5 total table locks 5  trx id 3742528 lock_mode X locks rec but not gap waiting lock hold time 0 wait time before grant 0 
*** (2) TRANSACTION:
TRANSACTION 3742527, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
12 lock struct(s), heap size 2936, 81 row lock(s)
MySQL thread id 1943, OS thread handle 0x7fe5b8e6eb00, query id 43123 localhost 127.0.0.1 root updating
UPDATE auth_sessions
                                                    SET last_activity_time= NAME_CONST('time_now',_latin1'2018-12-21 05:45:39' COLLATE 'latin1_swedish_ci')
                                                    WHERE id= NAME_CONST('temp_session_id',481)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 470949 page no 6 n bits 160 index `PRIMARY` of table `xfusion_auth_engine`.`auth_sessions` trx table locks 5 total table locks 5  trx id 3742527 lock mode S locks rec but not gap lock hold time 0 wait time before grant 0 
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 470949 page no 6 n bits 160 index `PRIMARY` of table `xfusion_auth_engine`.`auth_sessions` trx table locks 5 total table locks 5  trx id 3742527 lock_mode X locks rec but not gap waiting lock hold time 0 wait time before grant 0 
*** WE ROLL BACK TRANSACTION (2)
------------
TRANSACTIONS

Схема таблицы - сеанс аутентификации

CREATE TABLE `auth_sessions` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Auto Increment ID',
    `user_id` VARCHAR(255) NULL DEFAULT NULL COMMENT 'User Email',
    `user_key` VARCHAR(255) NULL DEFAULT NULL COMMENT 'User Key',
    `application_key` VARCHAR(255) NULL DEFAULT NULL COMMENT 'Application Key',
    `created` DATETIME NULL DEFAULT NULL COMMENT 'Session Creation Time',
    `expires` DATETIME NULL DEFAULT NULL COMMENT 'Session Expiration Time',
    `is_logged_in` TINYINT(4) NULL DEFAULT NULL COMMENT 'Tells whether user is logged in or not ',
    `session_key` VARCHAR(255) NULL DEFAULT NULL COMMENT 'Session Key per user per application key',
    `last_activity_time` DATETIME NULL DEFAULT NULL COMMENT 'Last recorded time for any activity',
    `session_key_bin` BINARY(16) NULL DEFAULT NULL COMMENT 'Binary ID of Session Key',
    PRIMARY KEY (`id`),
    INDEX `ix_session_key_bin` (`session_key_bin`)
)

COLLATE='latin1_swedish_ci'
ENGINE=InnoDB

;

Любая подсказка или решение для разрешенияэтот вопрос?

1 Ответ

0 голосов
/ 21 декабря 2018

Если у вас есть транзакция с несколькими выписками (которой у вас нет):

Иногда для решения проблем, подобных этим, нужно иметь

SELECT ... WHERE id= 481  FOR UPDATE;

до UPDATE, но внутри транзакции.

Не все взаимоблокировки можно предотвратить.Лучше быть готовым справиться с тупиками.Этот конкретный, вероятно, может быть правильно обработан следующим образом:

План A (предпочтительно): Воспроизвести UPDATE.

План B (вероятно, в порядке, учитывая цель запроса): Игнорировать тупик.

План C (я не знаю, сработает ли он; если он сработает, то должен устранить этот вид тупика):

UPDATE auth_sessions
    SET   last_activity_time = NOW()
    WHERE last_activity_time != NOW()
      AND id = 481;

Идея состоит в том, чтобы не пытаться обновить, еслизначение уже установлено на желаемое время.

...