Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Postgres: optimistic locking, pessimistic locking, concurrency control, database, transaction

В чем разница между оптимистической и пессимистической блокировками?

Вопрос проверяет понимание стратегий управления конкурентным доступом к данным в многопользовательских системах, что необходимо для предотвращения конфликтов и обеспечения целостности данных.

Короткий ответ

Оптимистическая блокировка предполагает, что конфликты при одновременном изменении данных редки. Она проверяет наличие конфликта только в момент сохранения, сравнивая версию данных. Пессимистическая блокировка заранее блокирует запись для других пользователей на всё время транзакции, предотвращая конфликты, но снижая параллелизм. Первая лучше для сценариев с низкой конкуренцией, вторая — для высокой, где конфликты часты.

Длинный ответ

В многопользовательских приложениях, где несколько клиентов могут одновременно пытаться изменить одни и те же данные, возникает проблема конкурентного доступа. Для её решения используются две основные стратегии: оптимистическая и пессимистическая блокировки. Они кардинально различаются в подходе к управлению параллелизмом.

Оптимистическая блокировка (Optimistic Locking)

Эта стратегия исходит из предположения, что конфликты при одновременном изменении данных случаются редко. Поэтому она не блокирует данные на время чтения. Вместо этого, при сохранении изменений, система проверяет, не изменились ли данные с момента их чтения. Обычно это реализуется с помощью поля версии (например, version или timestamp).

Пример работы:

  1. Пользователь А читает запись с id=1 и version=5.
  2. Пользователь Б читает ту же запись с version=5.
  3. Пользователь А изменяет запись и пытается сохранить её с условием WHERE id=1 AND version=5. Сохранение проходит успешно, версия обновляется до 6.
  4. Пользователь Б также изменяет свою локальную копию и пытается сохранить с условием WHERE id=1 AND version=5. Эта операция завершится ошибкой, так как текущая версия в БД уже равна 6. Пользователю Б нужно будет перечитать актуальные данные и повторить операцию.

Пример кода на Python с использованием SQLAlchemy:

# Модель с полем версии
class Product(Base):
    __tablename__ = 'products'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    stock = Column(Integer)
    version = Column(Integer, default=1)

# Оптимистическое обновление
def update_product_stock(session, product_id, new_stock):
    product = session.query(Product).get(product_id)
    old_version = product.version
    product.stock = new_stock
    product.version = old_version + 1
    
    # Попытка сохранить с проверкой версии
    rows_updated = session.query(Product).filter(
        Product.id == product_id,
        Product.version == old_version
    ).update({
        'stock': new_stock,
        'version': old_version + 1
    })
    
    if rows_updated == 0:
        session.rollback()
        raise Exception('Конфликт версий: данные были изменены другим пользователем.')

Пессимистическая блокировка (Pessimistic Locking)

Эта стратегия предполагает, что конфликты очень вероятны. Поэтому при чтении данных с целью их последующего изменения запись сразу блокируется для других транзакций (обычно с помощью конструкций вроде SELECT ... FOR UPDATE в SQL). Блокировка удерживается до конца текущей транзакции (commit или rollback).

Пример работы:

  1. Пользователь А начинает транзакцию и выполняет SELECT * FROM accounts WHERE id=1 FOR UPDATE. Запись с id=1 блокируется.
  2. Пользователь Б пытается выполнить аналогичный SELECT ... FOR UPDATE для той же записи. Его запрос будет ждать, пока пользователь А не завершит свою транзакцию.
  3. Пользователь А изменяет баланс и выполняет COMMIT, освобождая блокировку.
  4. Только после этого запрос пользователя Б выполняется.

Пример на SQL:

-- Транзакция пользователя А
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; -- Блокировка установлена
-- ... выполняем вычисления нового баланса
UPDATE accounts SET balance = 1500 WHERE id = 1;
COMMIT; -- Блокировка снимается

-- Транзакция пользователя Б будет ждать на SELECT ... FOR UPDATE,
-- пока пользователь А не сделает COMMIT.

Сравнение и применение

  • Производительность и масштабируемость: Оптимистическая блокировка обычно обеспечивает лучшую производительность и масштабируемость, так как не требует долгосрочных блокировок. Пессимистическая блокировка может стать узким местом при высокой конкуренции.
  • Частота конфликтов: Используйте пессимистическую блокировку, когда конфликты действительно часты и стоимость повторной попытки операции (при оптимистическом подходе) высока. Например, при обработке финансовых транзакций или бронировании последнего билета.
  • Длительность транзакций: Пессимистическая блокировка плохо подходит для длительных транзакций (например, когда пользователь долго редактирует форму), так как блокировка удерживается долго. В таких случаях предпочтительна оптимистическая стратегия.

Вывод: Оптимистическая блокировка — это стратегия "проверь и потом сохрани", идеальная для сценариев с высокой читаемостью и редкими конфликтами, например, в веб-приложениях с большим количеством чтений. Пессимистическая блокировка — стратегия "заблокируй, потом изменяй", которая необходима в системах с высокой конкуренцией за одни и те же данные, где важно гарантировать последовательность изменений, таких как банковские системы или системы управления запасами.

Уровень

  • Рейтинг:

    4

  • Сложность:

    6

Навыки

  • Postgres

    Postgres

  • SQL

Ключевые слова

#optimistic locking

#pessimistic locking

#concurrency control

#database

#transaction

Подпишись на Java Developer в телеграм