LOCK — bloquear una tabla
LOCK [ TABLE ] [ ONLY ]nombre[ * ] [, ...] [ INmodo_bloqueoMODE ] [ NOWAIT ] dondemodo_bloqueoes uno de: ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
LOCK TABLE obtiene un bloqueo a nivel de tabla, esperando
si es necesario a que se liberen los bloqueos en conflicto. Si
NOWAIT is especifica, LOCK
TABLE no espera para adquirir el bloqueo deseado: si no
se puede adquirir de inmediato, el comando se aborta y se emite un
error. Una vez obtenido, el bloqueo se mantiene durante el resto de la
transacción actual. (No existe el comando UNLOCK
TABLE; los bloqueos siempre se liberan al final de la
transacción).
Cuando se bloquea una vista, todas las relaciones que aparecen en la consulta de definición de la vista también se bloquean de forma recursiva con el mismo modo de bloqueo.
Al adquirir bloqueos automáticamente para comandos que hacen referencia a
tablas, PostgreSQL siempre utiliza el modo de bloqueo
menos restrictivo posible. LOCK TABLE se utiliza en los
casos en que se pueda necesitar un bloqueo más restrictivo.
Por ejemplo, supón que una aplicación ejecuta una transacción en el nivel de
aislamiento READ COMMITTED y necesita garantizar que los
datos de una tabla permanezcan estables durante la transacción.
Para lograr esto, podrías obtener el modo de bloqueo SHARE
sobre la tabla antes de realizar la consulta. Esto evitará cambios de datos
concurrentes y garantizará que las lecturas posteriores de la tabla vean
una vista de datos estable de los datos confirmados, porque el modo de bloqueo
SHARE entra en conflicto con el bloqueo ROW EXCLUSIVE
adquirido por los escritores, y tu sentencia LOCK TABLE esperará
hasta que cualquier poseedor concurrente de bloqueos en modo nombre IN SHARE MODEROW
EXCLUSIVE confirme o deshaga su transacción. Por lo tanto, una vez
obtenido el bloqueo, no hay escrituras no confirmadas pendientes; además,
ninguna puede comenzar hasta que liberes el bloqueo.
Para lograr un efecto similar cuando se ejecuta una transacción en el nivel de
aislamiento REPEATABLE READ o SERIALIZABLE,
debes ejecutar la sentencia LOCK TABLE antes de ejecutar
cualquier SELECT o sentencia de modificación de datos.
La vista de datos de una transacción REPEATABLE READ o
SERIALIZABLE se congelará cuando comience su primer
SELECT o sentencia de modificación de datos. Un
LOCK TABLE posterior en la transacción seguirá evitando
escrituras concurrentes, pero no garantizará que lo que lee la transacción
corresponda a los últimos valores confirmados.
Si una transacción de este tipo va a cambiar los datos en la tabla, entonces
debería usar el modo de bloqueo SHARE ROW EXCLUSIVE en lugar
del modo SHARE. Esto asegura que solo se ejecute una
transacción de este tipo a la vez. Sin esto, es posible un bloqueo mutuo
(deadlock): dos transacciones podrían adquirir el modo SHARE,
y luego no poder adquirir también el modo ROW EXCLUSIVE para
realizar realmente sus actualizaciones. (Ten en cuenta que los propios bloqueos
de una transacción nunca entran en conflicto, por lo que una transacción puede
adquirir el modo ROW EXCLUSIVE cuando posee el modo
SHARE, pero no si alguien más posee el modo SHARE).
Para evitar bloqueos mutuos, asegúrate de que todas las transacciones adquieran
bloqueos en los mismos objetos en el mismo orden, y si hay múltiples modos de bloqueo
involucrados para un solo objeto, las transacciones siempre deben adquirir
primero el modo más restrictivo.
Se puede encontrar más información sobre los modos de bloqueo y las estrategias de bloqueo en la Section 13.3.
nombre
El nombre (opcionalmente calificado por esquema) de una tabla existente para
bloquear. Si se especifica ONLY antes del nombre de la tabla,
solo se bloquea esa tabla. Si no se especifica ONLY, se bloquea
la tabla y todas sus tablas descendientes (si las hay). Opcionalmente, se puede
especificar * después del nombre de la tabla para indicar
explícitamente que se incluyen las tablas descendientes.
El comando LOCK TABLE a, b; es equivalente a
LOCK TABLE a; LOCK TABLE b;. Las tablas se bloquean
una por una en el orden especificado en el comando LOCK
TABLE.
modo_bloqueoEl modo de bloqueo especifica con qué bloqueos entra en conflicto este bloqueo. Los modos de bloqueo se describen en la Section 13.3.
Si no se especifica ningún modo de bloqueo, se utiliza ACCESS
EXCLUSIVE, el modo más restrictivo.
NOWAIT
Especifica que LOCK TABLE no debe esperar a que
se liberen los bloqueos en conflicto: si el/los bloqueo(s) especificado(s)
no se pueden adquirir de inmediato sin esperar, la transacción
se aborta.
Para bloquear una tabla, el usuario debe tener el privilegio adecuado para el
modo_bloqueo especificado.
Si el usuario tiene privilegios MAINTAIN,
UPDATE, DELETE o
TRUNCATE en la tabla, se permite cualquier modo_bloqueo. Si el usuario tiene privilegios
INSERT en la tabla, se permite ROW EXCLUSIVE
MODE (o un modo de menor conflicto como se describe en la Section 13.3). Si un usuario tiene privilegios
SELECT en la tabla, se permite ACCESS SHARE
MODE.
El usuario que realiza el bloqueo en la vista debe tener el privilegio correspondiente
sobre ella. Además, por omisión, el propietario de la vista debe tener los
privilegios pertinentes en las relaciones base subyacentes, mientras que el
usuario que realiza el bloqueo no necesita ningún permiso en las relaciones
base subyacentes. Sin embargo, si la vista tiene
security_invoker establecido en true
(consulta la CREATE VIEW),
el usuario que realiza el bloqueo, en lugar del propietario de la vista, debe tener los
privilegios correspondientes en las relaciones base subyacentes.
LOCK TABLE es inútil fuera de un bloque de transacción: el
bloqueo se mantendría solo hasta la finalización de la sentencia. Por lo tanto,
PostgreSQL informa un error si se utiliza LOCK
fuera de un bloque de transacción.
Usa
BEGIN y
COMMIT
(o ROLLBACK)
para definir un bloque de transacción.
LOCK TABLE solo se ocupa de los bloqueos a nivel de tabla,
por lo que los nombres de los modos que involucran ROW son
todos denominaciones erróneas. Estos nombres de modos generalmente deben leerse
como una indicación de la intención del usuario de adquirir bloqueos a nivel de
fila dentro de la tabla bloqueada. Además, el modo ROW EXCLUSIVE
es un bloqueo de tabla que se puede compartir. Ten en cuenta que todos los modos de
bloqueo tienen una semántica idéntica en lo que respecta a LOCK TABLE,
difiriendo solo en las reglas sobre qué modos entran en conflicto con cuáles. Para
obtener información sobre cómo adquirir un bloqueo a nivel de fila real, consulta la
Section 13.3.2 y la The Locking Clause
en la documentación de SELECT.
Obtener un bloqueo SHARE en una tabla de clave primaria
cuando se van a realizar inserciones en una tabla de clave foránea:
BEGIN WORK;
LOCK TABLE films IN SHARE MODE;
SELECT id FROM films
WHERE name = 'Star Wars: Episode I - The Phantom Menace';
-- Hacer ROLLBACK si no se devolvió el registro
INSERT INTO films_user_comments VALUES
(_id_, 'GREAT! I was waiting for it for so long!');
COMMIT WORK;
Tomar un bloqueo SHARE ROW EXCLUSIVE en una tabla de clave
primaria cuando se va a realizar una operación de eliminación:
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;
No existe LOCK TABLE en el estándar SQL,
el cual en su lugar utiliza SET TRANSACTION para especificar
los niveles de concurrencia en las transacciones. PostgreSQL
también admite eso; consulta la SET TRANSACTION para obtener detalles.
A excepción de los modos de bloqueo ACCESS SHARE, ACCESS EXCLUSIVE,
y SHARE UPDATE EXCLUSIVE, los modos de bloqueo de
PostgreSQL y la sintaxis de LOCK TABLE
son compatibles con los presentes en Oracle.