Найти в Дзене
Записки о Java

SELECT FOR UPDATE в Java и PostgreSQL: когда, зачем и как это работает

Стек: Java 11, PostgreSQL 12+, JDBC, Spring Boot, Hibernate
Цель: понять, когда использовать SELECT FOR UPDATE, как он блокирует строки, какие есть альтернативы, и как фреймворки управляют блокировками “под капотом”. Представьте: два пользователя одновременно пытаются купить последний товар на складе. Без блокировок: Итог: товар продан дважды, хотя был один. 💡 Решение: заблокировать строку при чтении, чтобы другой поток не мог её прочитать до завершения транзакции. SELECT * FROM products WHERE id = 1 FOR UPDATE; ⚠️ Важно: блокировка удерживается до конца транзакции (COMMIT или ROLLBACK). ✅ Ключевые моменты:Транзакция обязательна,
Блокировка автоматически снимается при коммите,
Не используйте FOR UPDATE вне транзакции — это бессмысленно.
PostgreSQL использует MVCC (Multi-Version Concurrency Control), но для блокировок применяет дополнительный механизм: SELECT * FROM products WHERE id = 1 FOR UPDATE NOWAIT; Блокировка SQL Описание FOR UPDATE SELECT ... FOR UPDATE Эксклюзивная бл
Оглавление
Рисунок: как работает SELECT FOR UPDATE в POSTGRESQL
Рисунок: как работает SELECT FOR UPDATE в POSTGRESQL

Стек: Java 11, PostgreSQL 12+, JDBC, Spring Boot, Hibernate
Цель: понять, когда использовать SELECT FOR UPDATE, как он блокирует строки, какие есть альтернативы, и как фреймворки управляют блокировками “под капотом”.

Зачем вообще нужны блокировки в БД?

Представьте: два пользователя одновременно пытаются купить последний товар на складе.

Без блокировок:

Рисунок: пример
Рисунок: пример

Итог: товар продан дважды, хотя был один.

💡 Решение: заблокировать строку при чтении, чтобы другой поток не мог её прочитать до завершения транзакции.

SELECT FOR UPDATE: что это и как работает?

Синтаксис (PostgreSQL):

SELECT * FROM products WHERE id = 1 FOR UPDATE;

Что делает:

  • Блокирует выбранные строки эксклюзивной блокировкой (Exclusive Lock).
  • Другие транзакции не могут читать эти строки с FOR UPDATE или FOR SHARE до коммита/отката.
  • Обычные SELECT (без FOR ...) продолжают работать (MVCC в действии!).
⚠️ Важно: блокировка удерживается до конца транзакции (COMMIT или ROLLBACK).

Как использовать в Java 11 (JDBC)

Рисунок: использование блокировок в JAVA, часть 1
Рисунок: использование блокировок в JAVA, часть 1
Рисунок: использование блокировок в JAVA, часть 2
Рисунок: использование блокировок в JAVA, часть 2

Ключевые моменты:Транзакция обязательна,
Блокировка
автоматически снимается при коммите,
Не используйте FOR UPDATE вне транзакции — это бессмысленно.

Под капотом: как PostgreSQL реализует FOR UPDATE

PostgreSQL использует MVCC (Multi-Version Concurrency Control), но для блокировок применяет дополнительный механизм:

  1. При SELECT FOR UPDATE:Находит видимую версию строки (согласно MVCC),
    Устанавливает
    блокировку уровня строки (tuple lock),
    Эта блокировка
    хранится в служебной таблице pg_locks.
  2. Другая транзакция, выполняющая FOR UPDATE той же строки:Блокируется (ожидает освобождения),

SELECT * FROM products WHERE id = 1 FOR UPDATE NOWAIT;

Другие виды блокировок в PostgreSQL

Блокировка

SQL

Описание

FOR UPDATE

SELECT ... FOR UPDATE

Эксклюзивная блокировка строки (для обновления)

FOR NO KEY UPDATE

SELECT ... FOR NO KEY UPDATE

Слабая эксклюзивная блокировка (не блокирует FOR KEY SHARE)

FOR SHARE

SELECT ... FOR SHARE

Совместная блокировка (разрешает другим читать, но не писать)

FOR KEY SHARE

SELECT ... FOR KEY SHARE

Самая слабая блокировка (разрешает почти всё, кроме удаления ключа)

💡 В 95% случаев вам нужен FOR UPDATE.

Как Spring Data JPA и Hibernate работают с блокировками

1. Spring Data JPA: @Lock

Риунок: пример
Риунок: пример

Под капотом Spring генерирует:

SELECT * FROM products WHERE id = ? FOR UPDATE

2. Hibernate: Session.lock()

Рисунок: пример
Рисунок: пример

3. Оптимистичная блокировка (без FOR UPDATE)

Рисунок: пример оптимистической блокировки в JAVA
Рисунок: пример оптимистической блокировки в JAVA

✅ Используйте оптимистичную блокировку, если конфликты редки.
❌ Используйте FOR UPDATE, если
конфликты часты (например, резервирование мест).

⚠️ Когда НЕ стоит использовать FOR UPDATE

Сценарий

Почему

Высоконагруженные системы

Блокировки снижают пропускную способность

Долгие транзакции

Блокировка удерживается долго → другие ждут → таймауты

Чтение без последующей записи

Нет смысла блокировать

Можно использовать оптимистичную блокировку

Она масштабируется лучше

Правило:
Используйте FOR UPDATE только для коротких транзакций с read-modify-write.