PostgreSQL在存储函数中获取并释放LOCK

时间:2015-03-11 18:27:27

标签: sql postgresql plpgsql

我有一个需要对多个大表执行长时间更新的函数。在更新期间,一次需要在EXCLUSIVE模式下锁定2-3个表。

由于并非所有表都需要同时锁定,理想情况下我只想锁定那些我当时正在更新的表,然后在完成后删除锁。

例如

-- Lock first pair of tables
LOCK TABLE tbl1_a IN EXCLUSIVE MODE;
LOCK TABLE tbl1_b IN EXCLUSIVE MODE;

-- Perform the update on tbl1_a and tbl1_b

-- Release the locks on tbl1_a and tbl1_b
--  HOW???

-- Proceed to the next pair of tables
LOCK TABLE tbl2_a IN EXCLUSIVE MODE;
LOCK TABLE tbl2_b IN EXCLUSIVE MODE;

不幸的是,在plpgsql中没有等效的UNLOCK语句。删除LOCK的常规方法是COMMIT事务,但这在函数内部是不可能的。

这有什么解决方案吗?在函数完成之前显式释放锁的某种方法?或者运行某种子事务(可能通过在单独的函数中运行每个更新)?

更新

我接受了没有解决方案。我将每个更新写入一个单独的函数并从数据库外部进行协调。谢谢大家。

3 个答案:

答案 0 :(得分:6)

没办法。 Postgres中的函数是原子的(总是在事务中),并且在事务结束时释放锁。而且还没有自主交易。

您可以使用advisory locks解决此问题。但那些不是一回事。所有竞争交易都必须发挥作用。不知道建议锁定的并发访问将破坏该方。

dba.SE上的代码示例:

或者你可能会在某些地方与dblink一起“欺骗”自治交易:

或者您重新评估您的问题并将其拆分为几个单独的交易。

答案 1 :(得分:1)

不可能。来自文档:一旦获得,通常会持有锁定直到交易结束。但是,如果在建立保存点后获取锁定,则在保存点回滚到的情况下立即释放锁定。这与ROLLBACK取消自保存点以来命令的所有效果的原则一致。对于在PL / pgSQL异常块中获取的锁也是如此:从块释放锁的错误逃脱释放在其中获取的锁。

http://www.postgresql.org/docs/9.3/static/explicit-locking.html

答案 2 :(得分:1)

在pg11中,您现在拥有PROCEDURE,可以通过COMMIT释放锁。我刚刚转换了一堆运行ALTER TABLE ... ADD FOREIGN KEY ...的并行执行函数,但遇到了很多死锁问题,而且效果很好。

https://www.postgresql.org/docs/current/sql-createprocedure.html