↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1 / 7.0 / 6.5 / 6.4

LOCK

LOCK — 锁定表

大纲

LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ]

其中 lockmode 可以是以下之一:

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

描述

LOCK TABLE 获取一个表级锁;如有必要,会等待任何冲突锁被释放。如果指定了 NOWAIT,LOCK TABLE 就不会等待获取所需的锁:如果无法立即获得,命令将被中止并报错。锁一旦获得,就会一直持有到当前事务结束。(没有 UNLOCK TABLE 命令;锁总是在事务结束时释放。)

锁定一个视图时,出现在该视图定义查询中的所有关系也会以相同的锁模式递归地被锁定。

在为引用表的命令自动获取锁时,PostgreSQL 总是尽可能使用限制最少的锁模式。LOCK TABLE 适用于可能需要更严格锁定的场景。例如,假设某个应用在 READ COMMITTED 隔离级别下运行事务,并且需要确保某个表中的数据在整个事务期间保持稳定。要做到这一点,可以在查询之前先对该表获取 SHARE 锁模式。这样可以阻止并发的数据更改,并确保后续对该表的读取看到已提交数据的稳定视图,因为 SHARE 锁模式与写入者获取的 ROW EXCLUSIVE 锁冲突,而 LOCK TABLE name IN SHARE MODE 语句会一直等待,直到所有并发持有 ROW EXCLUSIVE 模式锁的事务提交或回滚。因此,一旦获得该锁,就不存在尚未提交的写入;而且在释放该锁之前,也不会有新的写入开始。

若要在 REPEATABLE READ 或 SERIALIZABLE 隔离级别的事务中达到类似效果,你必须在执行任何 SELECT 或数据修改语句之前执行 LOCK TABLE 语句。REPEATABLE READ 或 SERIALIZABLE 事务的数据视图,会在其第一条 SELECT 或数据修改语句开始时冻结。在事务稍后再执行 LOCK TABLE 仍然可以阻止并发写入 — 但它不能保证该事务读取到的是最新已提交的值。

如果这类事务还要修改表中的数据,那么它应使用 SHARE ROW EXCLUSIVE 锁模式,而不是 SHARE 模式。这样可以确保同一时间只有一个这类事务在运行。否则就可能发生死锁:两个事务都可能先获得 SHARE 模式,然后都无法再获得实际执行更新所需的 ROW EXCLUSIVE 模式。(注意,事务自己的锁永远不会互相冲突,因此事务在持有 SHARE 模式时仍可获得 ROW EXCLUSIVE 模式,但前提是没有其他人持有 SHARE 模式。)为避免死锁,要确保所有事务都按相同顺序对相同对象获取锁;如果同一对象需要多种锁模式,则事务应始终先获取限制最严格的模式。

关于锁模式和锁策略的更多信息,请参见第 13.3 节。

参数

name #

要锁定的现有表的名称(可选模式限定)。如果在表名前指定了 ONLY,则只有该表会被锁定。如果未指定 ONLY,则该表及其所有后代表(如果有)都会被锁定。也可以在表名后指定*,以显式表明包含后代表。

命令 LOCK TABLE a, b;等效于 LOCK TABLE a; LOCK TABLE b;。这些表会按 LOCK TABLE 命令中指定的顺序逐个锁定。

lockmode #

锁模式指定该锁会与哪些锁冲突。锁模式见第 13.3 节。

如果未指定锁模式,则使用限制最严格的 ACCESS EXCLUSIVE 模式。

NOWAIT #

指定 LOCK TABLE 不等待任何冲突锁被释放:如果指定的锁无法在不等待的情况下立即获得,事务就会中止。

注解

要锁定一个表,用户必须拥有与所指定 lockmode 对应的权限。如果用户在该表上拥有 MAINTAIN、UPDATE、DELETE 或 TRUNCATE 权限,则允许使用任意 lockmode。如果用户在该表上拥有 INSERT 权限,则允许使用 ROW EXCLUSIVE MODE(或冲突更少的锁模式,见第 13.3 节)。如果用户在该表上拥有 SELECT 权限,则允许使用 ACCESS SHARE MODE。

在视图上执行锁定操作的用户必须对该视图拥有相应权限。此外,默认情况下,视图所有者必须对底层基关系拥有相关权限,而执行锁定操作的用户不需要对底层基关系拥有任何权限。但是,如果视图的 security_invoker 设置为 true(参见 CREATE VIEW),那么必须由执行锁定操作的用户而不是视图所有者,对底层基关系拥有相关权限。

LOCK TABLE 在事务块外毫无用处:锁只会一直持有到该语句结束。因此,如果在事务块外使用 LOCK,PostgreSQL 会报告错误。请使用 BEGIN 和 COMMIT(或 ROLLBACK)来定义事务块。

LOCK TABLE 只处理表级锁,因此名称中带有 ROW 的模式其实都不准确。这些模式名称通常应理解为:用户打算在被锁定的表中获取行级锁。此外,ROW EXCLUSIVE 模式本身也是一种可共享的表锁。请记住,就 LOCK TABLE 而言,所有锁模式的语义完全相同,差别只在于哪些模式彼此冲突。关于如何获取真正的行级锁,请参阅第 13.3.2 节和锁定子句(后者位于 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 来指定事务的并发级别。PostgreSQL 也支持这一点;详见 SET TRANSACTION。

除 ACCESS SHARE、ACCESS EXCLUSIVE 和 SHARE UPDATE EXCLUSIVE 锁模式外,PostgreSQL 的锁模式和 LOCK TABLE 语法与 Oracle 中的对应语法兼容。

报告文档问题

阅读 上游文档. 通过 PostgreSQL 文档反馈表单.