PostgreSQL 在存储函数中获取并释放 LOCK
PostgreSQL obtain and release LOCK inside stored function
我有一个函数需要对多个大表执行长时间更新。在更新期间,一次需要在 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 的正常方法是提交事务,但这在函数内部是不可能的。
有什么解决办法吗?在函数完成之前显式释放锁的某种方法?或 运行 某种子事务(可能 运行 在单独的函数中进行每个更新)?
更新
我承认没有解决办法。我会将每个更新写入一个单独的函数并从数据库外部进行协调。谢谢大家。
在 Postgres 11 或更高版本中,考虑允许事务控制的 PROCEDURE
。参见:
- Do stored procedures run in database transaction in Postgres?
有功能,没办法。 Postgres 中的函数是原子的(总是在事务中)并且锁在事务结束时释放。
您可以使用 advisory locks 来解决这个问题。但那些不是一回事。所有相互竞争的交易都必须一起进行。不知道咨询锁的并发访问会破坏聚会。
dba.SE 上的代码示例:
或者您可能会通过 dblink 的“作弊”自治事务到达某个地方:
- How do I do large non-blocking updates in PostgreSQL?
- Does Postgres support nested or autonomous transactions?
或者您重新评估您的问题并将其拆分为几个单独的事务。
不可能。来自文档:一旦获得,锁通常会一直保持到事务结束。但是如果在建立保存点后获取了锁,回滚到保存点后,锁会立即释放。这与 ROLLBACK 取消保存点以来命令的所有效果的原理是一致的。这同样适用于在 PL/pgSQL 异常块中获取的锁:块中的错误逃逸会释放在其中获取的锁。
http://www.postgresql.org/docs/9.3/static/explicit-locking.html
在 pg11 中,您现在有 PROCEDURE
s 可以让您通过 COMMIT
释放锁。我刚刚转换了一堆并行执行的函数 运行 ALTER TABLE ... ADD FOREIGN KEY ...
,但有很多死锁问题,而且效果很好。
https://www.postgresql.org/docs/current/sql-createprocedure.html
我有一个函数需要对多个大表执行长时间更新。在更新期间,一次需要在 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 的正常方法是提交事务,但这在函数内部是不可能的。
有什么解决办法吗?在函数完成之前显式释放锁的某种方法?或 运行 某种子事务(可能 运行 在单独的函数中进行每个更新)?
更新
我承认没有解决办法。我会将每个更新写入一个单独的函数并从数据库外部进行协调。谢谢大家。
在 Postgres 11 或更高版本中,考虑允许事务控制的 PROCEDURE
。参见:
- Do stored procedures run in database transaction in Postgres?
有功能,没办法。 Postgres 中的函数是原子的(总是在事务中)并且锁在事务结束时释放。
您可以使用 advisory locks 来解决这个问题。但那些不是一回事。所有相互竞争的交易都必须一起进行。不知道咨询锁的并发访问会破坏聚会。
dba.SE 上的代码示例:
或者您可能会通过 dblink 的“作弊”自治事务到达某个地方:
- How do I do large non-blocking updates in PostgreSQL?
- Does Postgres support nested or autonomous transactions?
或者您重新评估您的问题并将其拆分为几个单独的事务。
不可能。来自文档:一旦获得,锁通常会一直保持到事务结束。但是如果在建立保存点后获取了锁,回滚到保存点后,锁会立即释放。这与 ROLLBACK 取消保存点以来命令的所有效果的原理是一致的。这同样适用于在 PL/pgSQL 异常块中获取的锁:块中的错误逃逸会释放在其中获取的锁。
http://www.postgresql.org/docs/9.3/static/explicit-locking.html
在 pg11 中,您现在有 PROCEDURE
s 可以让您通过 COMMIT
释放锁。我刚刚转换了一堆并行执行的函数 运行 ALTER TABLE ... ADD FOREIGN KEY ...
,但有很多死锁问题,而且效果很好。
https://www.postgresql.org/docs/current/sql-createprocedure.html