Postgresql 中文操作指南

LOCK

LOCK — 锁定表格

Synopsis

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

where lockmode is one of:

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

Description

LOCK TABLE 获取表级锁定,在必要时等待任何冲突锁释放。如果指定了 NOWAITLOCK TABLE 不会等待获取所需的锁:如果不能立即获取,则会中止命令并发出错误。获取后,锁将保持在当前事务的剩余时间内。(没有 UNLOCK TABLE 命令;锁总是会在事务结束时释放。)

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

为引用表的命令自动获取锁定时,PostgreSQL 始终使用最小限制的锁模式。当需要进行更加严格的锁定时, LOCK TABLE 会提供案例。例如,假设应用程序在 READ COMMITTED 隔离级别运行,并且需要确保表中的数据在事务期间保持稳定。要实现此目的,可以在查询之前获取表上的 SHARE 锁定模式。这将阻止并发数据更改,并确保随后对表的读取看到已提交数据的稳定视图,因为 SHARE 锁定模式与写入者获取的 ROW EXCLUSIVE 锁定冲突,并且您的 LOCK TABLE _name IN SHARE MODE_ 语句将等待任何持有 ROW EXCLUSIVE 模式锁定的并发持有者提交或回滚。因此,一旦获得锁,就没有未提交的写操作待处理;此外,在您释放锁之前,也不能开始任何操作。

要获得与在 REPEATABLE READSERIALIZABLE 隔离级别下运行事务相同的成效,您必须在执行任何 SELECT 或数据修改语句之前执行 LOCK TABLE 语句。 REPEATABLE READSERIALIZABLE 事务对数据所获得的视图会在其第一个 SELECT 或数据修改语句开始时冻结。 LOCK TABLE 的事务稍后仍将阻止并发写入,但它不能确保事务所读取的内容与最新的已提交值相符。

如果此类事务要更改表中的数据,那么它应该使用 SHARE ROW EXCLUSIVE 锁模式,而不是 SHARE 模式。这确保了同一时间只会运行一次此类事务。不进行此操作,则可能导致死锁:两个事务都可能获取 SHARE 模式,然后都无法获取 ROW EXCLUSIVE 模式以实际执行更新。(请注意,事务自身锁之间不会冲突,因此当事务持有 SHARE 模式时,它可以获取 ROW EXCLUSIVE 模式,但如果其他人持有 SHARE 模式,则不行。)为了避免死锁,请确保所有事务按照相同的顺序获取对相同对象的锁,并且如果涉及一个对象有多个锁模式,那么事务应首先总是获取最严格的模式。

有关锁模式和锁策略的更多信息,请参见 Section 13.3

Parameters

  • name

    • 要锁定的现有表的名称(可选择进行架构限定)。如果在表名称之前指定了 ONLY ,则只锁定该表。如果未指定 ONLY ,则锁定该表及其所有后代表(如果存在)。另外,也可以在表名称之后指定 * 以明确表明包括后代表。

    • 命令 LOCK TABLE a, b; 等同于 LOCK TABLE a; LOCK TABLE b; 。表按照 LOCK TABLE 命令中指定的顺序逐个锁定。

  • lockmode

    • 锁模式指定了此锁与哪些锁冲突。锁模式在 Section 13.3 中进行了描述。

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

  • NOWAIT

    • 指定 LOCK TABLE 不应等待任何冲突的锁释放:如果无法立即获取指定的锁(们)而无需等待,则中止事务。

Notes

若要锁定表,用户必须具有指定 lockmode 的正确权限,或者作为该表的拥有者或超级用户。如果用户对该表拥有 UPDATEDELETETRUNCATE 权限,则允许任何 lockmode 。如果用户对该表拥有 INSERT 权限,则允许 ROW EXCLUSIVE MODE (或 Section 13.3 中描述的非冲突模式)。如果用户对该表拥有 SELECT 权限,则允许 ACCESS SHARE MODE

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

LOCK TABLE 在事务块外部无用:锁只会在语句完成之前一直保持。因此,如果 LOCK 在事务块外部使用,PostgreSQL 将报告错误。使用 BEGINCOMMIT (或 ROLLBACK )定义事务块。

LOCK TABLE 只处理表级锁,因此 涉及 ROW 的模式名都是错误的。一般应将这些模式名视为表明用户意在获取所锁表中的行级锁。另外, ROW EXCLUSIVE 模式是一种可共享表锁。请注意,就 LOCK TABLE 而言,所有锁模式的语义都相同,只有关于哪些模式与哪些模式冲突的规则不同。有关如何获取实际行级锁的信息,请参见 SELECT 文档中的 Section 13.3.2The Locking Clause

Examples

当要对外部键表执行插入操作时,获取主键表的 SHARE 锁:

BEGIN WORK;
LOCK TABLE films IN SHARE MODE;
SELECT id FROM films
    WHERE name = 'Star Wars: Episode I - The Phantom Menace';
-- Do ROLLBACK if record was not returned
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;

Compatibility

SQL 标准中没有 LOCK TABLE ,而是使用 SET TRANSACTION 指定事务的并发级别。PostgreSQL 也支持该标准;请参见 SET TRANSACTION 了解更多详情。

除了 ACCESS SHAREACCESS EXCLUSIVESHARE UPDATE EXCLUSIVE 锁模式,PostgreSQL 锁模式和 LOCK TABLE 语法与 Oracle 中的锁模式和语法兼容。