MySql InnoDB Repeatable Read Неожиданное поведение блокировок

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

об этом также говорится в официальной документации

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

Но неожиданно столкнулся с поведением при появлении классического тупика чтения / обновления:

  1. Уровень изоляции REPEATABLE READ (также воспроизводится с помощью READ COMMITTED)

  2. Транзакция 1 читает строку (НЕ блокировка в режиме совместного использования).

  3. Транзакция 2 читает ту же строку (ТАКЖЕ НЕ блокировка в режиме совместного использования). тогда

  4. Транзакция 1 пытается обновить эту строку.

  5. Транзакция 2 также пытается обновить эту строку.

После последнего шага innoDB обнаруживает взаимоблокировку (ниже находится ПОСЛЕДНИЙ ОБНАРУЖЕННЫЙ ТЕРМО): ---------------- 31.03.2017 16:07:03 0x1f58 *** (1) ТРАНЗАКЦИЯ : TRANSACTION 413412, АКТИВНЫЙ 20-секундный начальный индекс, чтение используемых таблиц mysql 1, заблокировано 1 LOCK WAIT 9 блокировок структур, размер кучи 1136, 6 блокировок строк, отменить записи журнала 3 MySQL thread id 33, дескриптор потока ОС 8148, идентификатор запроса 102005 localhost 127.0.0.1 обновление корня

/* update Order */ update `Order` set ... <fields to update>

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413412 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0

*** (2) TRANSACTION:
TRANSACTION 413413, ACTIVE 11 sec starting index read
mysql tables in use 1, locked 1
9 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 3
MySQL thread id 28, OS thread handle 8024, query id 102008 localhost 127.0.0.1 root updating

/* update Order */ update `Order` set ...<fields to update>

*** (2) **HOLDS THE LOCK(S):**
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0

 *** WE ROLL BACK TRANSACTION (2)

Я не могу понять, что происходит, почему Транзакция 2

Удерживает ЗАМОК (S)

поэтому, если innoDB все же не использует согласованное чтение с моментальным снимком и устанавливает S-блокировки, это не соответствует тому факту, который написан в официальном руководстве.


person Gleb Egunov    schedule 31.03.2017    source источник


Ответы (1)


Не делай этого. Если вы, возможно, обновляете строку, но при этом нуждаетесь в значении, используйте SELECT ... FOR UPDATE;. Просто сделай это и забудь о tx_isolation. Обычно это превращает тупик в задержку. (См. innodb_lock_wait_timeout, который по умолчанию составляет более 50 секунд.)

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

person Rick James    schedule 01.04.2017