Spec-Zone .ru
спецификации, руководства, описания, API
|
Если Вы запрашиваете данные и затем вставляете или обновляете связанные данные в пределах той же самой
транзакции, постоянного клиента SELECT
оператор не дает достаточную защиту. Другие
транзакции могут обновить или удалить те же самые строки, которые Вы только запросили. InnoDB
поддерживает два типа блокировки
чтений, которые предлагают дополнительную безопасность:
SELECT ... LOCK IN SHARE MODE
устанавливает коллективную блокировку на
любых строках, которые читаются. Другие сеансы могут считать строки, но не могут изменить их до Ваших
фиксаций транзакции. Если какая-либо из этих строк была изменена другой транзакцией, которая еще не
фиксировала, Ваш запрос ожидает до той транзакции концы и затем использует последние значения.
Для индексируют записи, с которыми поиск встречается, SELECT ... FOR UPDATE
блокирует строки и любые связанные элементы
индекса, то же самое, как будто Вы вышли UPDATE
оператор для тех строк.
Другие транзакции блокируются от обновления тех строк от выполнения SELECT ... LOCK IN SHARE MODE
, или от чтения данных в определенных
уровнях изоляции транзакции. Непротиворечивые чтения игнорируют любой набор блокировок на записях,
которые существуют в представлении чтения. (Старые версии записи не могут быть заблокированы; они
восстанавливаются, применяя отмену,
входит в систему копия в памяти записи.)
Эти пункты прежде всего полезны, имея дело с или структурированными данными графика с древовидной структурой, или в единственной таблице или в разделении через многократные таблицы. Вы пересекаете края или древовидные ответвления от одного места до другого, резервируя право возвратиться и изменить любое из этих значений "указателя".
Все блокировки, установленные 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
не хорошее решение потому что, если два пользовательских
чтения счетчик одновременно, по крайней мере один из них заканчивает мертвой блокировке, когда это пытается
обновить счетчик.
Вот два способа реализовать чтение и постепенное увеличение счетчика без интерференции от другой транзакции:
Сначала обновите счетчик, постепенно увеличивая это 1, затем считайте это и
используйте новое значение в CHILD
таблица. Любая другая транзакция,
которая пытается считать счетчик, ожидает до Ваших фиксаций транзакции. Если другая транзакция находится
в середине этой той же самой последовательности, Ваша транзакция ожидает до других фиксаций.
Сначала выполните чтение блокировки встречного
использования FOR UPDATE
, и затем постепенно увеличьте счетчик:
SELECT counter_field FROM child_codes FOR UPDATE;UPDATE child_codes SET counter_field = counter_field + 1;
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
оператор просто получает информацию об идентификаторе (определенный для
текущего соединения). Это не получает доступ ни к какой таблице.