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

Posted

技术标签:

【中文标题】PostgreSQL在存储函数中获取和释放LOCK【英文标题】:PostgreSQL obtain and release LOCK inside stored function 【发布时间】:2015-03-11 18:27:26 【问题描述】:

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

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

例如。

-- 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 事务,但这在函数内部是不可能的。

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

更新

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

【问题讨论】:

【参考方案1】:

Postgres 11 或更高版本中,考虑允许事务控制的 PROCEDURE。见:

Do stored procedures run in database transaction in Postgres?

有了函数,就没有办法。 Postgres 中的函数是原子的(总是在事务中),锁在事务结束时释放。

您也许可以使用advisory locks 解决此问题。但那些不是一回事。所有竞争性交易都必须配合。不知道咨询锁的并发访问会破坏聚会。

dba.SE 上的代码示例:

Postgres UPDATE ... LIMIT 1

或者您可能会通过 dblink “欺骗”自主事务:

How do I do large non-blocking updates in PostgreSQL? Does Postgres support nested or autonomous transactions?

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

【讨论】:

由于函数是原子的,如果我们在一个函数中锁定一个表,然后在其中调用另一个函数,则不需要锁定同一个表,因为它已经被第一个(外部)锁定在自己的事务中起作用,对吧?如果我们在第二个函数中锁定同一张表,它将被“省略”,因为该表已经被锁定,并且它会像我们在第二个函数中不再锁定它一样工作,对吗? @Ignacio:没错。锁在事务中一路累积。并在最后发布。无需再次锁定表(具有相同的锁定强度)。 非常感谢欧文!您在 PostgreSQL 相关主题中的贡献很棒!【参考方案2】:

在 pg11 中,您现在拥有 PROCEDUREs,它允许您通过 COMMIT 释放锁。我刚刚转换了一堆运行 ALTER TABLE ... ADD FOREIGN KEY ... 的并行执行函数,但存在很多死锁问题,并且运行良好。

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于PostgreSQL在存储函数中获取和释放LOCK的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程--Lock

java面试题之synchronized和lock有什么区别

PostgreSQL LOCK(锁)

PostgreSQL LOCK(锁)

synchronized与Lock的区别

synchronized与Lock的区别