Блокировки: SHARE, UPDATE, FOR UPDATE

Что такое блокировки и зачем они нужны? 🔒

Блокировки в SQL — это механизм контроля доступа к данным при одновременной работе нескольких транзакций. Они предотвращают конфликты при чтении и изменении одних и тех же строк разными пользователями.

Представьте ситуацию: два клиента бронируют один и тот же билет на концерт. Без блокировок может возникнуть двойное бронирование — и это лишь один из примеров проблем, которые решают блокировки.


Типы блокировок в SQL

В PostgreSQL и других СУБД есть несколько ключевых типов блокировок строк. Разберём три самых важных:

1. SHARE — блокировка для чтения 📖

Эта блокировка ставится, когда транзакция читает данные и хочет гарантировать, что они не изменятся до её завершения.

BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR SHARE;
-- Другие транзакции могут тоже ставить SHARE, но не UPDATE/FOR UPDATE
COMMIT;

🔹 Когда использовать?
- Когда нужно прочитать данные и быть уверенным, что они не изменятся до конца транзакции.
- Например, проверка баланса перед списанием средств.


2. UPDATE — блокировка для изменения ✏️

Блокировка UPDATE автоматически ставится при изменении строки (через UPDATE или DELETE). Она предотвращает одновременное изменение одной записи разными транзакциями.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- Если другая транзакция попытается изменить эту же строку, она будет ждать
COMMIT;

🔹 Особенности:
- Совместима с SHARE, но не с другими UPDATE или FOR UPDATE.
- Автоматически устанавливается при UPDATE/DELETE.


3. FOR UPDATE — эксклюзивная блокировка ⚡

Самая строгая блокировка. Гарантирует, что другие транзакции не смогут ни читать (с FOR SHARE), ни изменять заблокированные строки.

BEGIN;
SELECT * FROM orders WHERE user_id = 5 FOR UPDATE;
-- Другие транзакции не смогут даже прочитать эти строки с FOR SHARE
COMMIT;

🔹 Когда использовать?
- Когда нужно получить монопольный доступ к данным (например, при бронировании билетов).
- Для предотвращения состояния гонки (race condition).


Практический пример: банковский перевод 💰

Допустим, мы делаем перевод денег между счетами. Без блокировок возможны ошибки:

-- ❌ Опасный код (без блокировок)
BEGIN;
-- Чтение без блокировки (может измениться до UPDATE!)
SELECT balance FROM accounts WHERE id = 1;
SELECT balance FROM accounts WHERE id = 2;
-- ...логика проверки...
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

А вот правильный вариант с блокировками:

-- ✅ Безопасный перевод
BEGIN;
-- Блокируем обе строки перед изменением
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
SELECT * FROM accounts WHERE id = 2 FOR UPDATE;
-- Теперь балансы гарантированно не изменятся
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

Совместимость блокировок 🧩

Запрос SHARE UPDATE FOR UPDATE
SHARE
UPDATE
FOR UPDATE

🔹 Как читать таблицу:
- Если текущая транзакция держит блокировку в строке, другие транзакции могут поставить только совместимые (✅).
- FOR UPDATE — самая строгая: она несовместима ни с чем.


Главные выводы 🎯

  1. SHARE — для безопасного чтения (другие могут читать, но не изменять).
  2. UPDATE — автоматически ставится при изменении строки.
  3. FOR UPDATE — эксклюзивный доступ (никто другой не может ни читать, ни изменять).
  4. Всегда блокируйте данные перед изменением, особенно в финансовых операциях!

Попробуйте применить эти блокировки в своих транзакциях — и ваши данные всегда будут в безопасности! 🔐

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео