LOCK

LOCK — заблокировать таблицу


Синтаксис

LOCK [ TABLE ] [ ONLY ] имя [ * ] [, ...][ IN  режим_блокировки ] [ NOWAIT ]  

где режимом_блокировки может быть:  

    ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
    | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

Описание

Команда LOCK TABLE получает блокировку уровня таблицы, при необходимости ожидая освобождения всех конфликтующих блокировок. Если указано NOWAIT, LOCK TABLE не ожидает освобождения желаемой блокировки: если ее нельзя получить немедленно, команда прерывается и выдается ошибка. После получения блокировка удерживается до конца текущей транзакции. (Команды UNLOCK TABLE не существует; блокировки всегда освобождаются в конце транзакции.)

Когда блокируется представление, все отношения, находящиеся в запросе определения представления, также рекурсивно блокируются с тем же режимом блокировки.

При автоматическом получении блокировок для команд, ссылающихся на таблицы, QHB всегда использует наименее ограничительный режим блокировки. Команда LOCK TABLE предназначена для случаев, когда может потребоваться более строгая блокировка. Например, предположим, что приложение выполняет транзакцию на уровне изоляции READ COMMITTED и должно обеспечить неизменность данных в таблице на протяжении всей транзакции. Для этого можно перед запросом получить для таблицы блокировку в режиме SHARE. Это предотвратит параллельные изменения данных и обеспечит стабильное представление зафиксированных данных при последующих чтениях таблицы, потому что режим блокировки SHARE конфликтует с запрашиваемой при записи блокировкой ROW EXCLUSIVE, а команда LOCK TABLE имя IN SHARE MODE будет ждать, пока все параллельные транзакции с блокировкой ROW EXCLUSIVE не будут зафиксированы или отменены. Таким образом, в момент получения такой блокировки не останется никаких открытых незафиксированных операций записи; более того, до снятия блокировки никто не сможет даже начать записывать.

Для достижения аналогичного эффекта при выполнении транзакции на уровнях изоляции REPEATABLE READ или SERIALIZABLE нужно выполнить команду LOCK TABLE перед выполнением первой SELECT или оператора, изменяющего данные. Представление данных для транзакции уровня REPEATABLE READ или SERIALIZABLE будет заморожено в тот момент, когда начнет выполняться этот запрос. Если команда LOCK TABLE выполняется в транзакции позже, она также предотвратит параллельную запись — но не гарантирует, что транзакция прочитает последние зафиксированные значения.

Если транзакция такого рода будет изменять данные в таблице, следует использовать вместо SHARE режим блокировки SHARE ROW EXCLUSIVE. Это гарантирует, что в один момент времени будет выполняться только одна транзакция такого типа. Без этого ограничения возможна взаимная блокировка: обе транзакции могут получить блокировки SHARE, после чего не смогут получить блокировку ROW EXCLUSIVE, чтобы действительно выполнить изменения. (Обратите внимание, что собственные блокировки транзакции никогда не конфликтуют, поэтому транзакция может получить блокировку ROW EXCLUSIVE, когда владеет блокировкой SHARE — но не тогда, когда блокировку SHARE удерживает кто-то другой.) Чтобы избежать взаимоблокировок, убедитесь, что все транзакции запрашивают блокировки одних и тех же объектов в одном и том же порядке, и если для одного объекта запрашиваются блокировки с разными режимами, то транзакции всегда должны сначала запрашивать наиболее строгую блокировку.

Дополнительную информацию о режимах и стратегиях блокировки можно найти в разделе Явная блокировка.


Параметры

имя

Имя блокируемой существующей таблицы (может быть дополнено схемой). Если перед именем таблицы указывается ONLY, то блокируется только эта таблица. Если ONLY не указано, то блокируются таблица и все ее потомки (если таковые имеются). После имени таблицы можно добавить необязательное указание *, чтобы явно обозначить, что включены и все дочерние таблицы.

Команда LOCK TABLE a, b; равнозначна команде LOCK TABLE a; LOCK TABLE b;. Таблицы блокируются одна за другой в порядке, указанном в команде LOCK TABLE.

режим_блокировки

Режим блокировки определяет, с какими блокировками эта блокировка конфликтует. Режимы блокировки описаны в разделе Явная блокировка.

Если режим блокировки не указан, то применяется самый строгий режим ACCESS EXCLUSIVE.

NOWAIT

Указывает, что LOCK TABLE не должна ожидать освобождения конфликтующих блокировок: если указанные блокировки не могут быть получены немедленно, без ожидания, транзакция прерывается.


Примечания

Команда LOCK TABLE ... IN ACCESS SHARE MODE требует права SELECT для целевой таблицы. Команда LOCK TABLE ... IN ROW EXCUSIVE MODE требует прав INSERT, UPDATE, DELETE или TRUNCATE для целевой таблицы. Все другие формы LOCK требуют для целевой таблицы прав UPDATE, DELETE или TRUNCATE.

Пользователь, выполняющий блокировку представления, должен иметь соответствующие права для этого представления. Кроме того, владелец представления должен иметь соответствующие права для нижележащих базовых отношений, но пользователь, выполняющий блокировку, не нуждается в каких-либо правах для них.

LOCK TABLE бесполезна вне блока транзакции: блокировка будет удерживаться только до завершения этого оператора. Поэтому если LOCK используется вне блока транзакции, QHB сообщает об ошибке. Для определения блока транзакции воспользуйтесь командами BEGIN и COMMIT (или ROLLBACK).

LOCK TABLE имеет дело только с блокировками уровня таблицы, и поэтому имена режимов, включающие ROW, не вполне корректны. Эти имена режимов обычно следует рассматривать как указывающие на намерение пользователя получить блокировки на уровне строк в заблокированной таблице. Кроме того, ROW EXCLUSIVE — это разделяемая блокировка таблицы. Имейте в виду, что для LOCK TABLE все режимы блокировки имеют одинаковую семантику, отличаясь только правилами, определяющими, какие режимы конфликтуют друг с другом. Информацию о том, как получить фактическую блокировку уровня строк, см. в подразделе Блокировки на уровне строк, а также в подразделе Предложение блокировки на справочной странице команды SELECT.


Примеры

Получение блокировки SHARE для первичного ключа таблицы при выполнении операций добавления в таблицу внешнего ключа:

BEGIN WORK;  
LOCK TABLE films IN SHARE MODE;  
SELECT id FROM films  
    WHERE name = 'Star Wars: Episode I - The Phantom Menace';  
-- Если запись не будет возвращена, выполнить ROLLBACK  
INSERT INTO films_user_comments VALUES  
    (id, 'GREAT! I was waiting for it for so long!');
COMMIT WORK;

Установка блокировки SHARE ROW EXCLUSIVE в таблице первичного ключа перед выполнением операции удаления:

BEGIN WORK;
LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM films_user_comments WHERE id IN
    (SELECT id FROM films WHERE rating < 5);
DELETE FROM films WHERE rating < 5;
COMMIT WORK;

Совместимость

В стандарте SQL нет команды LOCK TABLE; вместо этого для указания уровней изоляции в транзакциях в нем используется команда SET TRANSACTION. QHB поддерживает и этот вариант; дополнительную информацию см. на справочной странице команды SET TRANSACTION.

За исключением режимов блокировки ACCESS SHARE, ACCESS EXCLUSIVE и SHARE UPDATE EXCLUSIVE, режимы блокировки и синтаксис команды LOCK TABLE в QHB совместимы с имеющимися в Oracle.