我的应用程序使用悲观锁定。当用户打开表单以更新记录时,应用程序执行此查询(表名称是示例性的):
begin;
select *
from master m
natural join detail d
where m.master_id = 123456
for update nowait;
查询锁定一个主行和几个(几十个)详细信息行。交易开放,直到用户确认或取消更新。
我需要知道哪些行(至少是主行)被锁定。我已经挖掘了文档和postgres wiki但没有成功。
是否可以列出所有锁定的行?
答案 0 :(得分:3)
有可能吗?可能是的,但它是Postgres的最大谜团。我想你需要为它编写自己的扩展名(*)。
但是,有一种简单的方法可以解决这个问题。您可以使用非常好的Postgres功能advisory locks。函数pg_try_advisory_lock(key1 int, key2 int)
的两个参数可以解释为: table oid (key1)和 row id (key2)。然后
select pg_try_advisory_lock(('master'::regclass)::integer, 123456)
锁定表 master 的行123456(如果它之前未锁定)。该函数返回布尔值。
更新后,必须释放锁定:
select pg_advisory_unlock(('master'::regclass)::integer, 123456)
最好的东西,锁定行列表:
select classid::regclass, objid
from pg_locks
where locktype = 'advisory'
咨询锁可能是常规锁的补充,也可以单独使用。第二个选项非常具有临界性,因为它可以显着简化代码。但是应该谨慎应用,因为您必须确保所有应用程序中的表上的所有更新(删除)都是通过此锁定来执行的。
(*)Mr. Tatsuo Ishii做了(我不知道,刚发现)。
答案 1 :(得分:3)
PostgreSQL 9.5为FOR UPDATE
添加了一个新选项,提供了一种直接的方法。
SELECT master_id
FROM master
WHERE master_id NOT IN (
SELECT master_id
FROM master
FOR UPDATE SKIP LOCKED);
这会锁定所有当前未锁定的行,因此请考虑一下这是否对您有用,尤其是在您的表很大的情况下。如果不出意外,您将要避免在开放交易中这样做。如果您的表格很大,您可以应用其他WHERE
条件并以块的形式逐步执行,以避免一次锁定所有内容。