Advisory-блокування (PostgreSQL) - блокування за довільним числом, яке не прив'язане до жодного рядка чи таблиці. База лише гарантує, що один ключ одночасно тримає лише одна сесія; що цей ключ означає - вирішує застосунок.
-- Чекати, доки звільниться
SELECT pg_advisory_lock(42);
-- ... робота ...
SELECT pg_advisory_unlock(42);
-- Не чекати: true, якщо взяли, false - якщо зайнято
SELECT pg_try_advisory_lock(hashtext('import:prices'));
-- Знімається автоматично в кінці транзакції
SELECT pg_advisory_xact_lock(42);
Коли це доречно:
- Захистити дію, а не рядок: «лише один процес імпорту одночасно», «лише один сервер виконує міграції під час деплою».
- Блокування того, чого ще немає: не можна взяти
FOR UPDATEна рядок, якого ще не створено, а advisory-ключ від, наприклад, email - можна. - Без зайвої інфраструктури: коли Redis для розподілених блокувань немає, а PostgreSQL уже є.
Пастки:
- Сесійні блокування живуть, поки живе з'єднання. Якщо процес «забув» зняти блокування, але з'єднання лишилося в пулі, ключ буде зайнятий безстроково. Транзакційний варіант (
_xact_) безпечніший. - З PgBouncer у режимі transaction pooling сесійні блокування ламаються: наступний запит може піти іншим з'єднанням.
- Ключ - число; рядкові ідентифікатори перетворюють хешем, і про можливі колізії варто пам'ятати.
MySQL має схожі GET_LOCK('name', timeout) / RELEASE_LOCK('name') з рядковими іменами.