LOCK — 锁定表
LOCK [ TABLE ] [ ONLY ]name
[ * ] [, ...] [ INlockmode
MODE ] [ NOWAIT ] wherelockmode
is one of: 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 MODEROW EXCLUSIVE
模式锁定下发生的并发持有者提交或回滚。因此,一旦获取锁定之后,将不会出现未提交的待解决写入;并且,在您释放锁定之前也无法开始任何写入。
在 REPEATABLE READ
或 SERIALIZABLE
隔离级别下运行事务时,为了达到类似效果,您必须在执行任何 SELECT
或数据修改语句之前执行 LOCK TABLE
语句。在事务的第一个 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'; -- 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;
SQL 标准中没有 LOCK TABLE
,而是使用 SET TRANSACTION
来指定交易的并发级别。PostgreSQL 也支持该功能;有关详细信息,请参见 SET TRANSACTION。
除了 ACCESS SHARE
、ACCESS EXCLUSIVE
和 SHARE UPDATE EXCLUSIVE
锁模式以外,PostgreSQL 锁模式和 LOCK TABLE
语法与 Oracle 中存在的锁模式和语法兼容。