> Пример использования FOR UPDATE в PostgreSQL (Go, PostgreSQL)
Уровень: senior · Роль: backend · Категория: Технические вопросы
Компании: Ozon
Стек: Go, PostgreSQL
> Пример ответа
FOR UPDATE в PostgreSQL используется для блокировки выбранных строк при выполнении SELECT, чтобы предотвратить их изменение другими транзакциями до завершения текущей. Это критично для сценариев с конкурентным доступом, например, при резервировании товаров или обработке очередей.
Пример на Go с использованием database/sql и pgx:
GOpackage mainimport ("context""fmt""log""github.com/jackc/pgx/v5/pgxpool")func reserveItem(ctx context.Context, pool *pgxpool.Pool, itemID int) error {tx, err := pool.Begin(ctx)if err != nil {return fmt.Errorf("begin tx: %w", err)}defer tx.Rollback(ctx) // откат при ошибке// Блокируем строку для обновленияvar quantity interr = tx.QueryRow(ctx,`SELECT quantity FROM inventory WHERE id = $1 FOR UPDATE`, itemID).Scan(&quantity)if err != nil {return fmt.Errorf("select for update: %w", err)}if quantity <= 0 {return fmt.Errorf("item out of stock")}// Обновляем количество_, err = tx.Exec(ctx,`UPDATE inventory SET quantity = quantity - 1 WHERE id = $1`, itemID)if err != nil {return fmt.Errorf("update: %w", err)}return tx.Commit(ctx)}func main() {pool, err := pgxpool.New(context.Background(), "postgres://user:pass@localhost/db")if err != nil {log.Fatal(err)}defer pool.Close()if err := reserveItem(context.Background(), pool, 1); err != nil {log.Printf("reservation failed: %v", err)}}
Ключевые моменты:
-
FOR UPDATEработает только внутри транзакции (блокBEGIN/COMMIT). -
Блокировка снимается при завершении транзакции (commit или rollback).
-
Если другая транзакция уже держит блокировку на строке, текущая будет ждать (таймаут можно задать через
NOWAITилиSKIP LOCKED). -
В Go используйте
pgxpoolдля управления пулом соединений и явные транзакции (Begin/Commit/Rollback).
Этот подход гарантирует атомарность операции "проверить и уменьшить остаток" без гонок данных.
> Похожие задачи по backend
Нужно ли использовать мьютексы для синхронизации при работе с каналами и горутинами в Go
Что такое снимок данных в PostgreSQL и как он работает
Спроектируй базу данных для электронной библиотеки с таблицами авторов, книг и читателей, опиши связи, индексы и ограничения
Как реализовать выдачу книги одному читателю с учетом уникальности и предотвращения конфликтов
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью