LOCK
LOCK — 显式锁定一个表
大纲
LOCK [ TABLE ]name[, ...] LOCK [ TABLE ]name[, ...] INlockmodeMODE wherelockmodeis one of: ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
Inputs
name要锁定的现有表的名称。
- ACCESS SHARE MODE
注意
这种锁模式会在被查询的表上自动获取。
这是限制性最低的锁模式。它只与 ACCESS EXCLUSIVE 模式冲突。它用于保护表不被并发的
ALTER TABLE、DROP TABLE和VACUUM FULL命令修改。- ROW SHARE MODE
注意
由
SELECT ... FOR UPDATE自动获取。与 EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。
- ROW EXCLUSIVE MODE
注意
由
UPDATE、DELETE和INSERT语句自动获取。与 SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。
- SHARE UPDATE EXCLUSIVE MODE
注意
由(不带
FULL的)VACUUM自动获取。与 SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。此模式保护表不被并发的模式更改和 VACUUM 影响。
- SHARE MODE
注意
由
CREATE INDEX自动获取。对整张表加共享锁。与 ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。此模式保护表不被并发数据更新影响。
- SHARE ROW EXCLUSIVE MODE
注意
这与 EXCLUSIVE MODE 类似,但允许别人持有 ROW SHARE 锁。
与 ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。
- EXCLUSIVE MODE
注意
此模式比 SHARE ROW EXCLUSIVE 限制性更强。它阻塞所有并发的 ROW SHARE/SELECT...FOR UPDATE 查询。
与 ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。此模式只允许并发的 ACCESS SHARE,也就是说,只有对该表的读取才能与持有此锁模式的事务并行进行。
- ACCESS EXCLUSIVE MODE
注意
由
ALTER TABLE、DROP TABLE、VACUUM FULL语句自动获取。这是限制性最高的锁模式,保护被锁表免受任何并发操作。注意
不带限定的
LOCK TABLE(即没有显式锁模式选项的命令)也会获取这种锁模式。与所有锁模式冲突。
Outputs
LOCK TABLE锁获取成功。
ERRORname: Table does not exist.如果
name不存在则返回此消息。
描述
LOCK TABLE
在事务期间控制对一个表的并发访问。PostgreSQL
在可能时总是使用限制性最低的锁模式。LOCK TABLE
用于你可能需要更严格锁定的场合。
RDBMS 锁定使用下列术语:
- EXCLUSIVE
排他锁阻止授予其他同类型的锁。(注意:ROW EXCLUSIVE 模式没有完全遵循这一命名约定,因为它在表级别是共享的;只对正在被更新的特定行是排他的。)
- SHARE
共享锁允许别人也持有同类型的锁,但阻止授予相应的 EXCLUSIVE 锁。
- ACCESS
锁定表模式。
- ROW
锁定单个行。
例如,假设一个应用以
READ COMMITTED
隔离级别运行事务,并且需要确保表中的数据在事务期间保持存在。为此,你可以在查询之前对该表取得
SHARE
锁模式。这将阻止并发数据更改,并确保随后对该表的读取操作看到处于实际当前状态的数据,因为
SHARE
锁模式与写者取得的任何
ROW
EXCLUSIVE 锁冲突,而你的
LOCK TABLE
语句会等待任何并发写操作提交或回滚。因此,一旦你取得了锁,就不存在未提交的写。
name IN SHARE MODE
注意
要在以 SERIALIZABLE 隔离级别运行事务时读取处于实际当前状态的数据,你必须在执行任何 DML 语句之前执行 LOCK TABLE 语句。可串行化事务的数据视图会在其第一条 DML 语句开始时冻结。
除上述要求外,如果事务要更改表中的数据,就应取得 SHARE ROW EXCLUSIVE 锁模式,以防止两个并发事务都试图以 SHARE 模式锁定该表、然后再试图更改表中数据时出现死锁——两者(隐式)取得的 ROW EXCLUSIVE 锁模式都与并发的 SHARE 锁冲突。
继续讨论上面提出的死锁(两个事务互相等待)问题:你应当遵循两条通用规则来防止死锁条件:
事务必须以相同的顺序对相同的对象获取锁。
例如,如果一个应用先更新行 R1 再更新行 R2(在同一个事务中),那么第二个应用如果稍后要更新行 R1(在单个事务中),就不应先更新行 R2。相反,它应按照与第一个应用相同的顺序更新行 R1 和 R2。
只有两个冲突锁模式之一是自冲突的(即同一时刻只能被一个事务持有)时,事务才应同时获取这两个锁模式。如果涉及多种锁模式,事务应总是先获取限制性最高的模式。
前面在讨论使用 SHARE ROW EXCLUSIVE 模式而非 SHARE 模式时已给出过这条规则的一个例子。
注意
PostgreSQL 确实会检测死锁,并会回滚至少一个等待中的事务来解决死锁。
锁定多个表时,命令
LOCK a, b; 等价于
LOCK a; LOCK b;。各表按
LOCK
命令中指定的顺序逐一锁定。
注意
LOCK ... IN ACCESS SHARE MODE 要求在目标表上具有
SELECT
权限。LOCK
的所有其他形式都要求
UPDATE 和/或
DELETE 权限。
LOCK 只在事务块(BEGIN...COMMIT)内部有用,因为锁在事务一结束就被丢弃。出现在任何事务块之外的
LOCK
命令构成一个自包含的事务,因此锁一取得就会被丢弃。
用法
演示在准备向外键表执行插入时,在主键表上获取一个 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;
兼容性
SQL92
SQL92 中没有
LOCK TABLE,而是使用
SET TRANSACTION
来指定事务的并发级别。我们也支持这一点;详见SET TRANSACTION。
除
ACCESS SHARE、ACCESS EXCLUSIVE 和
SHARE UPDATE EXCLUSIVE
锁模式外,PostgreSQL
的锁模式和
LOCK TABLE
语法与
Oracle(TM)
中的对应语法兼容。