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
语句。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
的正确权限,或成为表的拥有者或超级用户。如果用户对表拥有 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 中的锁模式和语法兼容。