LOCK [ TABLE ] name LOCK [ TABLE ] name [, ...] IN lockmode MODE 这里 lockmode 可以是下列之一∶ ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
要锁定的现存表的名字(可以有模式修饰)。
这是最小限制的锁模式,只与 ACCESS EXCLUSIVE 模式冲突。 它用于保护被查询的表免于被并行的 ALTER TABLE, DROP TABLE 和 VACUUM FULL 对同一表操作的语句修改。
注意: SELECT 命令对被引用的表请求一个这个锁模式。 通常,任何只读取一个表,而不会修改该表的查询都请求这个锁模式。
与 EXCLUSIVE 和 ACCESS EXCLUSIVE 锁模式冲突。
注意: SELECT FOR UPDATE 命令在目标表上请求这个锁模式 (以及任何其它引用了,但是并非是 FOR UPDATE 的表上的 ACCESS SHARE 锁)。
与 SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。
注意: 命令 UPDATE,DELETE,和 INSERT 在目标表上请求这个锁模式(加上在任何其它引用了的表上的 ACCESS SHARE 锁)。 通常,这个锁模式强被任何修改表中数据的查询请求。
和SHARE UPDATE EXCLUSIVE,SHARE,SHARE ROW EXCLUSIVE, EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突.这个模式保护一个表不被并行的(事务进行)模式修改和VACUUM修改。
Note: 由 VACUUM (没有 FULL) 自动要求.
与 ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE, SHARE ROW EXCLUSIVE,EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。这个模式防止一个表的并行数据更新。
注意: CREATE INDEX 请求此锁。
与 ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE, SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。
注意: 任何 PostgreSQL 都会不会自动请求此锁。
与 ROW SHARE,ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE, SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE 和 ACCESS EXCLUSIVE 模式冲突。 这个模式只允许并发的 ACCESS SHARE,也就是说只有从表中读取数据 可以和一个持有这个锁模式的事务并发执行.
注意: 任何 PostgreSQL 都会不会自动请求此锁。
与所有锁模式冲突。这个锁模式保证锁的持有者是以任意方式访问该表的唯一事务。
注意: 由语句 ALTER TABLE, DROP TABLE,VACUUM FULL 请求。它也是没有声明任何锁模式的 LOCK TABLE 命令的缺省锁模式。
LOCK TABLE 获取一个表级别的锁,如果必要,会等待任何冲突的锁释放。 一旦获取了这个锁,那么这个锁就会在当前事务余下的时间里一直保持。 (没有 UNLOCK TABLE 命令;锁总是在事务结束的时候释放。)
在为那些引用了表的命令请求锁的时候,PostgreSQL 在可能的情况下,总是使用限制性最小的锁模式。 LOCK TABLE 是在你需要更严格的锁定的时候使用的工具。
比如,假设一个应用以 READ COMMITTED 隔离级别运行一个事务,并且需要确保表中的数据在事务的过程中保持稳定。 为了实现这个目标,你可以在查询开始之前获取一个 SHARE 锁模式。 这样将避免并发的数据改变并且保证随后对表的读取都看到那些已经提交的数据的稳定视图, 因为 SHARE 锁与写入事务请求的 ROW EXCLUSIVE 锁冲突,并且你的 LOCK TABLE name IN SHARE MODE 语句将等待任何 ROW EXCLUSIVE 模式持有者的提交或者回滚。因此,一旦你获取了这个锁, 那么就不在有未提交的写入事务在等待;并且再你释放这个锁之前也没有人能开始这样的事务。
注意: 要想在以 SERIALIZABLE 隔离级别运行的事务里实现类似的效果, 你就需要在任何 DML 语句之前执行 LOCK TABLE 语句。 一个可串行化的事务的数据视图将在它的第一个 DML 语句开始的时候冻结。 稍后的 LOCK 将仍然阻止并发的写入 --- 但是它不能保证事务读取的东西对应最后提交的数值。
如果一个这类的事务准备修改表中的数据,那么它应该使用 SHARE ROW EXCLUSIVE 锁模式,而不是SHARE 模式。 这样就保证了任意时刻只有一个这类的事务运行。没有这个的话,就有可能死锁: 两个事务可能都要请求 SHARE 模式,然后就不能再请求 ROW EXCLUSIVE 模式自动执行它们的更新。 (请注意,一个事务自己的锁从来不会冲突,所以一个事务可以再持有 SHARE 模式的时候请求 ROW EXCLUSIVE --- 但是不能在任何其它人持有 SHARE 模式的时候请求。)
我们可以遵循两个通用的规则来避免死锁:
不同事务在对同一个对象请求锁的顺序应该相同。
比如,如果一个应用先更新行 R1 然后更新行 R2 (在同一个事务里), 那么第二个应用不应该先更新行 R2 然后稍后又更新行 R1(在同一个事务里)。 第二个应用应该和第一个应用的更新顺序一样,先更新行 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 命令形成一个自包含的事务, 所以,这样的锁在获取之后就马上被丢弃了。
RDBMS 锁定使用下面的标准术语:
一个排他锁,阻止其它同类型锁的获取。
一个共享锁,允许其它(事务)同样持有同类型锁,但是阻止其它事务获取对应的 EXCLUSIVE 锁。
锁定表模式。
锁定独立的行。
PostgreSQL 并没有精确地遵循这些属于。 LOCK TABLE 只对付表级别地锁,所以所有涉及 ROW 的模式名都是用词不当。 这些模式名应该理解为用户企图在一个被锁定的表里面获取一个行级别的锁。 请记住,只要是 LOCK TABLE,那么所有锁模式都有同样的语意。 区别只是在哪个模式和哪个模式冲突的规则上。
演示在往一个外键表上插入时在有主键的表上使用 SHARE 的锁:
BEGIN WORK; LOCK TABLE films IN SHARE MODE; SELECT id FROM films WHERE name = 'Star Wars: Episode I - The Phantom Menace'; -- 如果记录没有返回则回滚 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里面没有LOCK TABLE ,可以使用 SET TRANSACTION 来声明当前事务的并发级别。 我们也支持这个,参阅 SET TRANSACTION 获取详细信息。
除了ACCESS SHARE,ACCESS EXCLUSIVE,和SHARE UPDATE EXCLUSIVE 锁模式外, PostgreSQL 锁模式和 LOCK TABLE 语句都与那些在 Oracle(TM) 里面的兼容。