Поведение MySQL «выбрать для обновления» - PullRequest
27 голосов
/ 13 января 2012

Согласно документации MySql, MySql поддерживает множественную блокировку гранулярности (MGL).

случай-1

Открыт терминал-1:

// подключен к mysql

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
|  2 |      0 |
|  3 |      0 |
|  4 |      0 |
|  5 |      0 |
+----+--------+
5 rows in set (0.00 sec)
mysql> 

оставил его открытым и открыл терминал-2:

// подключен к mysql

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;

<!-- Hangs here. and after some time it says-->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Хотя есть много строк для извлечения, T2 ждет, пока t1 не завершится.

случай-2

Левый терминал-1 как есть. Теперь в терминале-2:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

<!-- case 2.1 -->
mysql> select id, status from tracking_number where id=1;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
+----+--------+
1 row in set (0.00 sec)

mysql> select id, status from tracking_number where id=2;
+----+--------+
| id | status |
+----+--------+
|  2 |      0 |
+----+--------+
1 row in set (0.00 sec)

<!-- case 2.2 -->
mysql> select * from tracking_number where id=2 for update;
<!-- Hangs here. and after some time -->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  1. Но почему в случае 1 T2 ожидает тот же набор строк, который заблокировал T1?

  2. Означает ли это, что неограниченный запрос на выборку (даже с параметром limint. Я пробовал также с другим диапазоном) блокирует всю таблицу?

  3. Есть ли способ разрешить независимой блокировке транзакций без указания поля записи (т. Е. Без использования , где field = value )?
  4. Обычно (или в соответствии с одновременной блокировкой Java) блокировка записи является исключительной, а чтение - нет. В случае 2.1, хотя записи находятся в режиме блокировки записи, как T2 может читать те же записи? Так как это разрешено, какой смысл его блокировать?
  5. Случай 2.2 понятен.

Открыт терминал и транзакция:

mysql> update tracking_number set status=4 where status=0 limit 5;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5  Changed: 5  Warnings: 0

Оставил его там и открыл еще один терминал и транзакция:

mysql> update tracking_number set status=5 where status=0 limit 5; 

T2 не удалось, пока я не совершил (или откат) T1.

  1. Почему это поведение?

1 Ответ

23 голосов
/ 20 июля 2012

Позвольте мне рассмотреть ваши дела и объяснить, как работают эти блокировки:

1 кейс

T1 хочет обновить некоторые строки в вашей тестовой таблице. Эта транзакция устанавливает блокировку IX для всей таблицы и блокировку X для первых 5 строк.

T2 хочет обновить некоторые строки в вашей тестовой таблице. Эта транзакция устанавливает блокировку IX (потому что IX совместимо с IX) на всю таблицу и пытается выполнить первые 5 строк, но не может этого сделать, потому что X не совместим с X

Итак, мы в порядке.

2,1 дело

T1 хочет обновить некоторые строки в вашей тестовой таблице. Эта транзакция устанавливает блокировку IX для всей таблицы и блокировку X для первых 5 строк.

T2 хочет выбрать несколько строк из вашей тестовой таблицы. И он не устанавливает никаких блокировок (поскольку InnoDB обеспечивает неблокирующее чтение)

2,1 кейс

T1 хочет обновить некоторые строки в вашей тестовой таблице. Эта транзакция устанавливает блокировку IX для всей таблицы и блокировку X для первых 5 строк.

T2 хочет обновить (выбрать для обновления) некоторые строки из вашей тестовой таблицы. Поместите IS на всю таблицу и попытайтесь установить S-блокировку в строке, но не получится, потому что X и S несовместимы.


Также всегда помните об уровне изоляции: разные уровни вызывают разные механизмы для освобождения / получения блокировок

Надеюсь, это поможет

...