MySQL эксклюзивный замок - PullRequest
2 голосов
/ 25 марта 2020

У нас есть таблицы ниже:

mysql> desc journeys ;
+---------------+------------+------+-----+---------+-------+
| Field         | Type       | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+-------+
| journey_id    | char(36)   | NO   | PRI | NULL    |       |
| is_completed  | tinyint(1) | NO   |     | 0       |       |
| user_id       | char(36)   | NO   |     | NULL    |       |
| created_at    | datetime   | NO   |     | NULL    |       |
| updated_at    | datetime   | NO   |     | NULL    |       |
| pack_id       | char(36)   | YES  | MUL | NULL    |       |
| family_id     | char(36)   | YES  | MUL | NULL    |       |
+---------------+------------+------+-----+---------+-------+

mysql> desc packs ;
+---------------+------------+------+-----+---------+-------+
| Field         | Type       | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+-------+
| pack_id       | char(36)   | NO   | PRI | NULL    |       |
| is_published  | tinyint(1) | NO   |     | 0       |       |
| order         | int(11)    | NO   |     | NULL    |       |
| created_at    | datetime   | NO   |     | NULL    |       |
| updated_at    | datetime   | NO   |     | NULL    |       |
| family_id     | char(36)   | NO   | MUL | NULL    |       |
+---------------+------------+------+-----+---------+-------+

Уровень изоляции - REPEATABLE_READ.

Согласно глоссарию здесь: https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_exclusive_lock

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

Логика c, которая у нас есть, выглядит так, как показано ниже (user_id принимает различные значения):

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = <user_id> FOR UPDATE ;
# COMMIT;

Ниже приведено небольшое тестирование. Я открываю одно окно терминала (терминал # 1) и выполняю следующие инструкции:

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = user_id_1 FOR UPDATE ;

Затем я открываю второе окно терминала (терминал # 2) и выполняю следующие инструкции:

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = user_id_2 FOR UPDATE ;

Терминал № 2 теперь останавливается, потому что мы никогда не совершали транзакцию на терминале № 1.

Я предполагал, что, поскольку условие на первом терминале № 1 отличается от утверждения в терминале № 2 о том, что второй терминал не будет ждать первого принятия. Я основываю свое предположение на определении исключительной блокировки, которая говорит, что исключительная блокировка предотвращает любую другую транзакцию от блокировки той же строки. Это неправильное предположение? Если да, как можно заблокировать строки, которые у нас есть в первом условии?

Кажется, что все по-другому, когда я использую первичный ключ в условии. В приведенном ниже случае терминал # 2 не ожидает фиксации терминала # 1.

terminal #1
START TRANSACTION;
SELECT * FROM journeys WHERE journey_id = journey_id_1 FOR UPDATE ;

Операции в терминале # 2

terminal #2
START TRANSACTION;
SELECT * FROM journeys WHERE journey_id = journey_id_2 FOR UPDATE ;

Что именно происходит с эксклюзивными блокировками, когда у нас есть условия, которые не включают первичные ключи? Мы закрываем весь стол?

1 Ответ

1 голос
/ 26 марта 2020

Да, вы блокируете все строки в таблице, когда у вас есть условие для неиндексированного столбца, например user_id.

Блокировки применяются ко всем "проверенным" строкам. Ваше условие WHERE user_id = <user_id> должно проверить все строки в таблице и проверить их одну за другой, чтобы убедиться, что они соответствуют значению <user_id>.

Оба запроса проверяют все набор строк, даже если они ищут разные заданные c значения <user_id>, поэтому они конфликтуют.

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

Это не имеет никакого отношения к уровню изоляции транзакции. Эти типы блокировок встречаются на всех уровнях изоляции транзакций.

...