Открыть сервис

Пессимистичная блокировка

Пессимистичная блокировка (англ. pessimistic locking) — это стратегия управления конкурентным доступом к данным в системах управления базами данных (СУБД) и других многопользовательских средах, при которой ресурс (строка, таблица, документ или объект) блокируется на время выполнения транзакции, чтобы предотвратить его изменение другими транзакциями. Данный подход основан на предположении, что конфликты между транзакциями происходят часто, и поэтому изоляция достигается за счёт упреждающего захвата ресурса.

Принцип работы

Пессимистичная блокировка реализуется через механизмы блокировок, предоставляемые СУБД. При старте транзакции, которая планирует изменить или прочитать данные, система немедленно накладывает блокировку на соответствующий объект. Тип блокировки определяет, какие операции других транзакций будут разрешены.

Основные типы блокировок

В реляционных СУБД (например, PostgreSQL, Oracle, MySQL) используются два основных типа блокировок:

  • Исключительная блокировка (Exclusive Lock, X-lock) — накладывается на ресурс, который будет изменён (операции INSERT, UPDATE, DELETE). Другие транзакции не могут ни читать, ни изменять этот ресурс до завершения блокирующей транзакции.
  • Разделяемая блокировка (Shared Lock, S-lock) — накладывается на ресурс, который только читается (операция SELECT). Другие транзакции могут также накладывать разделяемые блокировки (читать данные), но не могут получить исключительную блокировку (изменять данные).

Процесс выполнения

  1. Транзакция A начинает работу и запрашивает блокировку на строку с идентификатором 1.
  2. Если блокировка свободна, СУБД предоставляет её. Транзакция A удерживает блокировку до своего завершения (COMMIT или ROLLBACK).
  3. Транзакция B пытается получить блокировку на ту же строку. В зависимости от настроек СУБД, она либо ожидает освобождения блокировки (режим ожидания с таймаутом), либо немедленно получает ошибку (например, «could not obtain lock»).
  4. После завершения транзакции A блокировка снимается, и транзакция B может продолжить работу.

Сравнение с оптимистичной блокировкой

Пессимистичная блокировка противопоставляется оптимистичной блокировке, при которой ресурс не блокируется на время транзакции, а конфликты выявляются только на этапе фиксации (COMMIT). Основные различия:

ХарактеристикаПессимистичная блокировкаОптимистичная блокировка
Предположение о конфликтахЧастые конфликтыРедкие конфликты
Время удержания блокировкиВся транзакцияТолько момент фиксации
ПроизводительностьСнижается при высокой конкуренцииВыше при низкой конкуренции
Риск взаимоблокировокВысокийНизкий
ПрименимостьОперации с высокой вероятностью измененийОперации с преимущественно чтением

Применение

Пессимистичная блокировка используется в сценариях, где целостность данных критична, а вероятность одновременного изменения одного ресурса высока. Типичные примеры:

  • Банковские системы — при списании средств со счёта необходимо гарантировать, что остаток не будет изменён другой транзакцией.
  • Системы бронирования — при бронировании последнего места на рейсе или в гостинице блокировка предотвращает двойное бронирование.
  • Редактирование документов — в системах управления контентом (CMS) или совместной работы (например, Microsoft SharePoint) пользователь, редактирующий документ, блокирует его для других.
  • ERP-системы — при проведении инвентаризации или отгрузке товара блокировка запасов предотвращает расхождения в учёте.

Недостатки и риски

Взаимоблокировки (Deadlocks)

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

  • Транзакция A блокирует строку 1 и запрашивает строку 2.
  • Транзакция B блокирует строку 2 и запрашивает строку 1.

Обе транзакции ждут друг друга бесконечно. СУБД обычно разрешает такие ситуации, принудительно откатывая одну из транзакций (обычно ту, которая начала работу позже).

Снижение производительности

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

Масштабируемость

Пессимистичная блокировка плохо масштабируется в распределённых системах и кластерах, так как требует координации блокировок между узлами. Для таких сред часто применяются распределённые блокировки (например, на основе ZooKeeper или Redis) или отказ от блокировок в пользу событийно-ориентированных архитектур.

Реализация в популярных СУБД

PostgreSQL

PostgreSQL поддерживает пессимистичную блокировку на уровне строк через команды SELECT ... FOR UPDATE (исключительная блокировка) и SELECT ... FOR SHARE (разделяемая блокировка). Пример:

``sql BEGIN; SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- Другие транзакции не могут изменить эту строку UPDATE accounts SET balance = balance - 100 WHERE id = 1; COMMIT; ``

Oracle

Oracle использует аналогичный синтаксис SELECT ... FOR UPDATE. Особенность: Oracle не блокирует чтение (SELECT без FOR UPDATE) даже при наличии исключительной блокировки — используется механизм Multi-Version Concurrency Control (MVCC), который позволяет читать «снимок» данных на момент начала запроса.

MySQL (InnoDB)

MySQL с движком InnoDB также поддерживает SELECT ... FOR UPDATE и SELECT ... FOR SHARE. InnoDB использует блокировки на уровне строк с поддержкой MVCC.

Microsoft SQL Server

SQL Server поддерживает пессимистичную блокировку через подсказки (hints) WITH (UPDLOCK), WITH (HOLDLOCK) и другие. По умолчанию используется оптимистичная блокировка на основе версий строк (snapshot isolation).

Альтернативы

В современных высоконагруженных системах пессимистичная блокировка часто заменяется или дополняется:

  • Оптимистичная блокировка — с использованием версий строк (например, поле version в таблице) или контрольных сумм.
  • Атомарные операции — например, UPDATE ... SET balance = balance - 100 WHERE id = 1 AND balance >= 100 (без явной блокировки).
  • Очереди сообщений — для асинхронной обработки запросов, исключающей одновременное изменение.
  • Распределённые блокировки — через внешние сервисы (Redis, ZooKeeper) для координации в микросервисной архитектуре.

Интересные факты

  • Термин «пессимистичная блокировка» происходит от пессимистичного предположения, что другая транзакция обязательно попытается изменить те же данные.
  • В некоторых СУБД (например, PostgreSQL) пессимистичная блокировка может приводить к «блокировкам на уровне страниц» (page-level locks), если блокировка строки не поддерживается из-за размера строки или настроек.
  • В системах реального времени (например, в телекоммуникациях) пессимистичная блокировка часто заменяется алгоритмами без блокировок (lock-free) для обеспечения предсказуемой задержки.

Источники

  • Гарсиа-Молина, Г., Ульман, Дж., Уидом, Дж. «Системы баз данных. Полный курс» (Database Systems: The Complete Book).
  • Документация PostgreSQL: «Chapter 13. Concurrency Control».
  • Документация Oracle: «Data Concurrency and Consistency».
  • Документация MySQL: «InnoDB Locking».
  • Кодд, Э. Ф. «A Relational Model of Data for Large Shared Data Banks» (1970).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →