1

你能解释一下这个奇怪的行为吗:

我有这个存储过程,它告诉我一行是否被锁定

CREATE OR REPLACE FUNCTION tg_availablega_is_unlocked(availablega_id integer)
  RETURNS boolean AS
$BODY$
DECLARE
  is_locked     boolean = FALSE;
BEGIN
  BEGIN
    PERFORM id FROM tg_availablega WHERE id = availablega_id
    FOR UPDATE NOWAIT;
  EXCEPTION 
    WHEN lock_not_available THEN
            is_locked := TRUE;
  END;
  RETURN not is_locked;
END;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

如果我开始交易并执行此操作:

SELECT "tg_availablega"."id",
       "tg_availablega"."isactive",
       "tg_availablega"."schedule",
       "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
WHERE (tg_availablega_is_unlocked("tg_availablega"."id")
       AND "tg_availablega"."zone_tg_id" = 1
       AND "tg_availablega"."isactive" = TRUE
       AND "tg_availablega"."schedule" = 20)
LIMIT 100
FOR
UPDATE;

它锁定并返回 100 行。如果我在其他事务中同时执行相同的操作,它会锁定并返回不同的 100 行。如果总行数为 101,则第一次执行返回 100 行,第二次执行仅返回 1 行。

但是如果我添加 ORDER BY 子句

SELECT "tg_availablega"."id",
       "tg_availablega"."isactive",
       "tg_availablega"."schedule",
       "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
WHERE (tg_availablega_is_unlocked("tg_availablega"."id")
       AND "tg_availablega"."zone_tg_id" = 1
       AND "tg_availablega"."isactive" = TRUE
       AND "tg_availablega"."schedule" = 20)
***ORDER BY "tg_availablega"."id"***
LIMIT 100
FOR
UPDATE;

然后第一个事务返回 100 个锁定行,第二个事务返回 NO ROWS

这是为什么?

4

1 回答 1

1

问题是函数 tg_availablega_is_unlocked 确实锁定了它检查的行。如果没有 order by,Postgres 不会访问所有行 - 因此不会在所有行上调用该函数。我想你的意思是:

select * from (
SELECT "tg_availablega"."id",
   "tg_availablega"."isactive",
   "tg_availablega"."schedule",
   "tg_availablega"."zone_tg_id"
FROM "tg_availablega"
 WHERE "tg_availablega"."zone_tg_id" = 1
   AND "tg_availablega"."isactive" = TRUE
   AND "tg_availablega"."schedule" = 20)
ORDER BY "tg_availablega"."id"
) a
where tg_availablega_is_unlocked(id)
limit 100
于 2013-02-26T14:09:31.087 回答