Почему нам нужно заблокировать таблицу mysql во время SELECT, когда начало транзакции вызывает фиксацию любой ожидающей транзакции? - PullRequest
0 голосов
/ 14 апреля 2020

На этой странице написано:

Начало транзакции приводит к фиксации любой ожидающей транзакции.

Итак, по сути, начинаем транзакцию действует как замок. Но затем на этой странице написано:

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

Эти утверждения кажутся мне противоречивыми, и как мне их согласовать? Для примера предположим, что я реализую кнопку «Мне нравится». Есть таблица со следующими столбцами (user, post, is_liked) и другая таблица, в которой хранится (post, total_likes). Таким образом, чтобы обработать подобный запрос, я бы хотел:

  1. Считать значение is_liked, которое является логическим значением, учитывая user и post.
  2. Затем переключить is_liked и обновлять как count

Все это нужно делать атомарно. Согласно первой ссылке, мне не нужно блокировать во время чтения, поскольку начало транзакции приводит к фиксации любой ожидающей транзакции. И если какая-то другая транзакция попытается обновить строки одновременно, она будет заблокирована моей ожидающей транзакцией. Но вторая ссылка говорит об обратном. Итак, кто прав и почему?

Вопрос 2: Если мне нужно заблокировать (что я подозреваю, что я делаю), я использую LOCK IN SHARE MODE или FOR UPDATE?

Ответы [ 2 ]

0 голосов
/ 14 апреля 2020

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

Но вы можете заблокировать таблицу, также в транзакции см.

Если вы запрашиваете данные, а затем вставляете или обновляете связанные данные в той же самой транзакция, обычный оператор SELECT не дает достаточной защиты. Другие транзакции могут обновлять или удалять те же строки, которые вы только что запросили. InnoDB поддерживает два типа блокировочных чтений, которые обеспечивают дополнительную безопасность:

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html

0 голосов
/ 14 апреля 2020

Запуск транзакции не похож на блокировку. Это недоразумение.

InnoDB по умолчанию реализует «оптимистическую блокировку c». Блокировки не получаются при запуске транзакции. Когда вы выполняете блокирующий оператор SQL, тогда блокируются по мере необходимости.

В вашем случае вы должны выбрать SELECT ... FOR UPDATE, потому что это то, что вы готовитесь сделать - обновите запись после прочтения.


Ваши комментарии:

Если вы используете SELECT LOCK IN SHARE MODE, это может привести к тупикам.

SESSION 1                       SESSION 2

SELECT ... LOCK IN SHARE MODE
ok
                                SELECT ... LOCK IN SHARE MODE
                                ok
UPDATE
waits
                                UPDATE
                                waits

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...