е добра идея само ако настоявате да заключите конкретен ред, което е не от какво имаш нужда. Просто искате всякакво квалифициращ, наличен (отключен) ред. Важната разлика е следната (цитирайки ръководството за Postgres 9.4):FOR UPDATE NOWAIT
С
NOWAIT
, операторът отчита грешка, вместо да чака, ако избран ред не може да бъде заключен незабавно.
Идентични заявки много вероятно ще се опитат да заключат един и същ произволен избор. FOR UPDATE NOWAIT
просто ще се спаси с изключение (което ще върне обратно цялата транзакция, освен ако не хванете грешката) и трябва да опитате отново.
Решението в моя препратен отговор на dba.SE използва комбинация от обикновен FOR UPDATE
в комбинация с pg_try_advisory_lock()
:
pg_try_advisory_lock
е подобен наpg_advisory_lock
, освен че функцията няма да чака заключването да стане достъпно. Той или ще получи заключването незабавно и ще върне true, или ще върне false, ако заключването не може да бъде получено незабавно.
Така че вашият най-добрият вариант е ... третата алтернатива:новата FOR UPDATE SKIP LOCKED
в Postgres 9.5, който реализира същото поведение без допълнително извикване на функция.
Ръководството за Postgres 9.5 сравнява двете опции, обяснявайки още малко разликата:
За да предотвратите операцията да чака други транзакции за извършване, използвайте или
NOWAIT
илиSKIP LOCKED
опция. СNOWAIT
, операторът отчита грешка, вместо да чака, ако избран ред не може да бъде заключен незабавно. СSKIP LOCKED
, всички избрани редове, които не могат да бъдат незабавно заключени, се пропускат.
На Postgres 9.4 или по-стара следващата ви най-добра опция е да използвате pg_try_advisory_xact_lock(id)
в комбинация с FOR UPDATE
както е показано в посочения отговор:
- Актуализиране на Postgres… ОГРАНИЧЕНИЕ 1
(Също така с реализация с FOR UPDATE SKIP LOCKED
.)
Строго погледнато, получавате произволни, а не наистина произволни избори. Това може да е важно разграничение.
Проверена версия на вашата заявка е в моя отговор на другия ви въпрос.