Spec-Zone .ru
спецификации, руководства, описания, API

14.2.3.4. Блокировка Чтений (SELECT ... FOR UPDATE и SELECT ... LOCK IN SHAREMODE)

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

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

Все блокировки, установленные LOCK IN SHARE MODE и FOR UPDATE запросы выпускаются, когда транзакция фиксируется или откатывается.

Отметить

Блокировка строк для использования обновления SELECT FOR UPDATE только применяется, когда автоматическая фиксация отключается (любой, начиная транзакцию с START TRANSACTION или устанавливая autocommit к 0. Если автоматическая фиксация включается, строки, соответствующие спецификацию, не блокируются.

Примеры использования

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

Во-первых, используйте непротиворечивое чтение, чтобы запросить таблицу PARENT и проверьте, что родительская строка существует. Можете Вы безопасно вставлять дочернюю строку к таблице CHILD? Нет, потому что некоторый другой сеанс мог удалить родительскую строку в момент между Вашим SELECT и Ваш INSERT, без Вас являющийся знающим об этом.

Чтобы избежать этой потенциальной проблемы, выполните SELECT использование LOCK IN SHARE MODE:

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

После LOCK IN SHARE MODE запросите возвращает родителя 'Jones', можно безопасно добавить дочернюю запись на CHILD таблица и фиксация транзакция. Любая транзакция, которая пытается читать или записать в применимую строку в PARENT таблица ожидает, пока Вы не заканчиваетесь, то есть, данные во всех таблицах находятся в непротиворечивом состоянии.

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

Здесь, LOCK IN SHARE MODE не хорошее решение потому что, если два пользовательских чтения счетчик одновременно, по крайней мере один из них заканчивает мертвой блокировке, когда это пытается обновить счетчик.

Вот два способа реализовать чтение и постепенное увеличение счетчика без интерференции от другой транзакции:

A SELECT ... FOR UPDATE читает последние доступные данные, устанавливая монопольные блокировки на каждой строке, которую они читают. Таким образом это устанавливает те же самые блокировки искавший SQL UPDATE установил бы на строках.

Предыдущее описание является просто примером как SELECT ... FOR UPDATE работы. В MySQL определенная задача генерирования уникального идентификатора фактически может быть выполнена, используя только одиночное обращение к таблице:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);SELECT LAST_INSERT_ID();

SELECT оператор просто получает информацию об идентификаторе (определенный для текущего соединения). Это не получает доступ ни к какой таблице.