この奇妙な振る舞いを説明してもらえますか:
行がロックされているかどうかを教えてくれるこのストアドプロシージャがあります
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 行が返され、2 回目の実行では残りの 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 個のロックされた行を返し、2 番目のトランザクションは NO ROWS を返します。
何故ですか?