Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що роблять SELECT ... FOR UPDATE і SKIP LOCKED?

SELECT ... FOR UPDATE читає рядки й блокує їх до кінця транзакції. Інші транзакції, які захочуть змінити ці рядки чи теж взяти FOR UPDATE, чекатимуть.

BEGIN;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;
-- тепер ніхто не змінить баланс, поки ми рахуємо
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

Так закривають гонку «прочитав → перевірив → записав»: друга транзакція прочитає баланс лише після того, як перша закомітить.

FOR UPDATE SKIP LOCKED (PostgreSQL 9.5+, MySQL 8.0+) - не чекати, а пропустити вже заблоковані рядки. Ідеально для черги завдань у таблиці: кілька воркерів беруть різні завдання без конфліктів.

SELECT id FROM jobs
WHERE status = 'pending'
ORDER BY id
LIMIT 1
FOR UPDATE SKIP LOCKED;

Саме так працює драйвер черги database у Laravel.

NOWAIT - не чекати, а одразу отримати помилку, якщо рядок зайнятий.

Пастки:

  • Блокування тримається до кінця транзакції. Без BEGIN (в autocommit) воно знімається одразу після запиту й нічого не захищає.
  • Довга транзакція з FOR UPDATE - це черга з інших запитів. Усередині не роблять HTTP-запитів чи інших повільних дій.
  • Блокування рядків у різному порядку в різних транзакціях - прямий шлях до deadlock.

Докладніше в документації: Явні блокування рядків

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання