MySQL InnoDB: разница между «ДЛЯ ОБНОВЛЕНИЯ» и «БЛОКИРОВКИ В РЕЖИМЕ ОБЩЕГО ОБЕСПЕЧЕНИЯ»

В чем точная разница между двумя блокирующими предложениями чтения:

SELECT ... FOR UPDATE

а также

SELECT ... LOCK IN SHARE MODE 

И зачем вам нужно использовать один над другим?


person pje    schedule 28.09.2015    source источник


Ответы (3)


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

И LOCK IN SHARE MODE, и FOR UPDATE гарантируют, что никакая другая транзакция не сможет обновить выбранные строки. Разница между ними заключается в том, как они обрабатывают блокировки при чтении данных.

LOCK IN SHARE MODE не препятствует тому, чтобы другая транзакция читала ту же заблокированную строку.

FOR UPDATE предотвращает другие блокирующие операции чтения той же строки (неблокирующие операции чтения по-прежнему могут читать эту строку; LOCK IN SHARE MODE и FOR UPDATE являются блокирующими операциями чтения).

Это имеет значение в таких случаях, как обновление счетчиков, когда вы считываете значение в одном выражении и обновляете значение в другом. Здесь использование LOCK IN SHARE MODE позволит 2 транзакциям прочитать одно и то же начальное значение. Таким образом, если счетчик был увеличен на 1 обеими транзакциями, конечный счетчик может увеличиться только на 1, поскольку обе транзакции изначально считывают одно и то же значение.

Использование FOR UPDATE заблокировало бы вторую транзакцию от чтения значения до завершения первой. Это обеспечит увеличение счетчика на 2.

person Aishwar    schedule 02.08.2016
comment
Согласно dev.mysql.com/doc/refman/ 5.7/en/innodb-locking-reads.html по крайней мере один из них оказывается в тупике - счетчик не увеличивается на 1 вместо 2, как вы указали. Любые идеи, почему может возникнуть взаимоблокировка? - person Anatolii Stepaniuk; 25.11.2017
comment
Если две транзакции блокируют строку в режиме SHARE, то ни одна из них вообще не сможет обновить строку — обновления не разрешены, пока другие транзакции удерживают блокировки. Что действительно произойдет в этой ситуации, так это то, что один из двух истечет время ожидания, освободит свою блокировку, а затем другой успешно обновит строку. Таким образом, с одной стороны, база данных останется согласованной, а с другой стороны, вы получите ненужный сбой. - person michalburger1; 24.01.2019
comment
В каком случае будет практический вариант использования блокировки режима SHARE, если вы не можете действительно обновить строку из-за взаимоблокировки, если есть другая транзакция, которая также удерживает блокировку режима SHARE? Это только в том случае, если вы не собираетесь ОБНОВЛЯТЬ/УДАЛИТЬ, но хотите полагаться на согласованность чтения? - person NeverEndingQueue; 26.02.2021
comment
Ответ в основном правильный, но если существует такая взаимоблокировка между двумя транзакциями, использующими FOR SHARE, то одна транзакция будет успешной, а другая нет. Если вы попробуете данный пример с тестовой базой данных и интерактивными клиентами mysql, вы увидите следующее поведение: обе транзакции будут считывать значение счетчика 1, но только одна из них сможет обновить его до значения 2. В зависимости от того, какая из транзакций получит обновление раньше будет заблокирован из-за блокировки чтения в другой транзакции. Когда другая транзакция попытается обновиться, она потерпит неудачу из-за взаимоблокировки, тогда первая разблокируется и завершится успешно. - person karagog; 17.03.2021

Для обновления --- Вы сообщаете Mysql, что выбранные строки могут быть обновлены на следующих шагах (до окончания этой транзакции), так что mysql не предоставляет никаких блокировок чтения для одного и того же набора строк любым другим транзакция в этот момент. Другая транзакция (для чтения/записи) должна дождаться завершения первой транзакции.

For Share — указывает Mysql, что вы выбираете строки из таблицы только для чтения, а не для изменения до конца транзакции. Любое количество транзакций может получить доступ к блокировке чтения строк.

Примечание. Есть вероятность возникновения тупиковой ситуации, если этот оператор (для обновления, для общего доступа) используется неправильно.

person charan teja    schedule 27.07.2018

В любом случае целостность ваших данных будет гарантирована, вопрос лишь в том, как база данных это гарантирует. Делает ли это это, вызывая ошибки времени выполнения, когда транзакции конфликтуют друг с другом (например, FOR SHARE), или делает это путем сериализации любых транзакций, которые могут конфликтовать друг с другом (например, FOR UPDATE)?

FOR SHARE (также известный как LOCK IN SHARE MODE): Транзакции сталкиваются с более высокой вероятностью сбоя из-за взаимоблокировки, поскольку они откладывают блокировку до момента получения оператора обновления (в этот момент они либо блокируются до тех пор, пока не будут сняты все блокировки чтения, либо завершаются ошибкой из-за блокировки). тупик, если выполняется другая запись). Тем не менее, только один клиент блокируется и в конечном итоге завершается успешно: другие клиенты потерпят тупик, если попытаются обновиться, поэтому только один из них добьется успеха, а остальным придется повторить свои транзакции.

ДЛЯ ОБНОВЛЕНИЯ: Транзакции не будут завершаться сбоем из-за взаимоблокировки, поскольку им не будет разрешено выполняться одновременно. Это может быть желательно, например, потому что упрощается рассмотрение многопоточности, если все обновления сериализуются для всех клиентов. Однако это ограничивает параллелизм, которого вы можете достичь, поскольку все остальные транзакции блокируются до тех пор, пока первая транзакция не будет завершена.

Профессиональный совет: в качестве упражнения я рекомендую потратить некоторое время, чтобы поиграть с локальной тестовой базой данных и парой клиентов mysql в командной строке, чтобы проверить это поведение для себя. Вот как я в конце концов сам понял разницу, потому что она может быть очень абстрактной, пока вы не увидите ее в действии.

person karagog    schedule 17.03.2021