Две транзакции не могут получить блокировку IX для одной и той же таблицы, MySql - PullRequest
1 голос
/ 29 марта 2019

У меня есть две сессии, делающие это.

Session 1>start transaction;
Session 1>select * from account for update;

Session 2>start transaction;
Session 2>select * from account for update; //waiting.

Так как блокировка IX совместима с блокировкой IX, не следует сеанс два и получить блокировку IX без ожидания.

Даже следующий наборstatemnts не работают.

Session 1>start transaction;
Session 1>select * from account where i = 1 for update;

Session 2>start transaction;
Session 2>select * from account where i = 2 for update; //waiting.

Уровень изоляции Repeatable Read.Отличаются ли вещи на этом уровне изоляции?

Источник совместимости это

Ответы [ 2 ]

2 голосов
/ 29 марта 2019

Два показанных вами запроса получают IX блокировки для таблицы, которые совместимы друг с другом.

Но SELECT...FOR UPDATE также продолжает получать блокировки X в проверяемых строках.Это конфликты, и поэтому второй SELECT...FOR UPDATE ждет.

В вашем примере, где один запрос для строк WHERE i = 1, а другой для строк WHERE i = 2, они не будут возвращать одинаковые строки,но они будут проверять перекрывающийся набор строк, если i не имеет индекса.Изучение строк означает, что InnoDB извлекает строки и затем проверяет их на соответствие условиям в предложении WHERE.Исходя из условий, он может пропускать некоторые проверяемые строки и возвращает проверенные строки только в том случае, если они проверяют значение true.

Если у вас есть индекс для i, InnoDB может исключить несовпадающие строки без изучения строк.В этих условиях ваш пример не покажет конфликта.

Session 1>ALTER TABLE account ADD INDEX (i);

Session 1>start transaction;
Session 1>select * from account where i = 1 for update;

Session 2>start transaction;
Session 2>select * from account where i = 2 for update; // does NOT wait
0 голосов
/ 29 марта 2019

При использовании SELECT ... FOR UPDATE MySQL попытается получить блокировку IX (намеренную исключительную блокировку) для всех строк и связанных записей индекса, которые запрос должен вернуть.Из документации :

Для записей индекса поиск встречает, блокирует строки и любые связанные записи индекса, так же, как если бы вы выполнили инструкцию UPDATE для этих строк.

Одна из ваших двух транзакций сначала выполнит FOR UPDATE, и в зависимости от того, какая из них удастся выполнить, будет заблокирована вся таблица, поскольку select является SELECT * без any WHERE clause.

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

SELECT * FROM yourTable WHERE id = 1 FOR UPDATE;
SELECT * FROM yourTable WHERE id = 2 FOR UPDATE;

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

...