Блокировка записи
Блокировка записи — это механизм управления параллельным доступом к данным, используемый в системах управления базами данных (СУБД), файловых системах и других многопользовательских средах для предотвращения конфликтов при одновременном изменении одного и того же ресурса. Блокировка записи гарантирует, что в любой момент времени только один процесс (транзакция или пользователь) может модифицировать данные, в то время как другие процессы, пытающиеся выполнить запись, ожидают снятия блокировки.
Назначение и принцип работы
Основная цель блокировки записи — обеспечение целостности данных (свойство ACID — изоляция транзакций) в условиях конкурентного доступа. Без блокировок два параллельных процесса могли бы одновременно изменить одну и ту же запись, что привело бы к потере одного из изменений или к некорректному состоянию данных.
Принцип работы блокировки записи заключается в следующем:
- Процесс, желающий изменить данные, запрашивает блокировку записи у СУБД.
- Если блокировка записи на данный ресурс не установлена другим процессом, СУБД предоставляет её, и процесс получает исключительное право на изменение.
- Другие процессы, пытающиеся установить блокировку записи на тот же ресурс, ставятся в очередь ожидания до освобождения блокировки.
- После завершения операции записи процесс снимает блокировку, и следующий процесс из очереди получает доступ.
Важно различать блокировку записи и блокировку чтения (shared lock). Блокировка чтения позволяет нескольким процессам одновременно читать данные, но запрещает их изменение. Блокировка записи, напротив, запрещает как запись, так и чтение (в большинстве СУБД) со стороны других процессов, чтобы избежать чтения «грязных» данных (dirty read).
Виды блокировок записи
Блокировки записи классифицируются по различным признакам.
По уровню гранулярности
- Блокировка строки (row-level lock) — блокируется только одна запись (строка таблицы). Наиболее гибкий и производительный вариант, используемый в современных СУБД (PostgreSQL, MySQL с движком InnoDB, Oracle).
- Блокировка страницы (page-level lock) — блокируется блок данных (страница), содержащий несколько строк. Менее гранулярный, но может быть эффективнее при работе с большими объёмами данных в некоторых СУБД (например, в старых версиях Microsoft SQL Server).
- Блокировка таблицы (table-level lock) — блокируется вся таблица. Простая в реализации, но сильно снижает параллелизм. Используется в СУБД с простыми механизмами (MyISAM для MySQL) или при выполнении массовых операций (например, ALTER TABLE).
- Блокировка базы данных (database-level lock) — блокируется вся база данных. Крайне редкая, применяется только в специализированных системах.
По способу реализации
- Пессимистичная блокировка (pessimistic locking) — блокировка устанавливается до начала операции записи и удерживается до её завершения. Предполагает, что конфликты вероятны, и предотвращает их заранее. Используется в высоконагруженных транзакционных системах.
- Оптимистичная блокировка (optimistic locking) — блокировка не устанавливается в момент начала операции. Вместо этого перед записью проверяется, не изменились ли данные с момента их чтения (обычно с помощью версии записи или временной метки). Если данные были изменены другим процессом, транзакция откатывается и повторяется. Используется в системах с низкой вероятностью конфликтов (например, веб-приложениях).
По времени удержания
- Краткосрочная блокировка (short-duration lock) — удерживается только на время выполнения одной операции (например, UPDATE). Типична для пессимистичных блокировок.
- Долгосрочная блокировка (long-duration lock) — удерживается на время всей транзакции. Обеспечивает более строгую изоляцию, но снижает параллелизм.
Механизмы реализации в популярных СУБД
PostgreSQL
PostgreSQL использует многовариантную модель управления параллельным доступом (MVCC), которая позволяет избежать многих конфликтов без явных блокировок. Однако блокировки записи всё же применяются:
- Блокировка строки на запись (RowExclusiveLock) — устанавливается при выполнении команд UPDATE, DELETE, INSERT.
- Блокировка таблицы — может быть установлена явно через команду
LOCK TABLE(например,ACCESS EXCLUSIVEдля полной блокировки). - Оптимистичная блокировка реализуется через проверку поля
xmin(идентификатор транзакции, создавшей версию строки).
MySQL (InnoDB)
InnoDB поддерживает блокировки на уровне строк с использованием механизма блокировок на основе индексов:
- Record lock — блокировка одной записи индекса.
- Gap lock — блокировка промежутка между записями индекса (предотвращает фантомное чтение).
- Next-key lock — комбинация record lock и gap lock.
- Блокировка таблицы — в InnoDB возможна, но не рекомендуется для обычных операций.
Microsoft SQL Server
SQL Server поддерживает блокировки на уровне строк, страниц и таблиц. Механизм блокировок динамически выбирает уровень гранулярности в зависимости от количества затрагиваемых строк. Блокировки записи могут быть эксклюзивными (X) или обновляемыми (U), причём U-блокировка позволяет избежать взаимоблокировок при чтении с намерением записи.
Oracle Database
Oracle использует MVCC и блокировки на уровне строк. Блокировка записи устанавливается только на изменяемые строки и не блокирует чтение (читатели не ждут писателей). Это достигается за счёт хранения старых версий данных в сегментах отката (undo segments).
Проблемы, связанные с блокировками записи
Взаимоблокировка (deadlock)
Ситуация, когда два или более процессов блокируют друг друга, ожидая освобождения ресурсов, занятых другими процессами. Например:
- Процесс A блокирует строку 1 и ждёт строку 2.
- Процесс B блокирует строку 2 и ждёт строку 1.
СУБД автоматически обнаруживает взаимоблокировки и прерывает одну из транзакций (обычно с откатом).
Голодание (starvation)
Ситуация, когда один процесс постоянно не может получить блокировку записи из-за того, что другие процессы непрерывно её захватывают. Обычно решается использованием очередей с приоритетами или алгоритмами справедливости.
Снижение производительности
Излишне строгие блокировки (например, блокировка всей таблицы) могут значительно снизить пропускную способность системы. Выбор оптимального уровня гранулярности — важная задача администрирования баз данных.
Применение в файловых системах
В файловых системах (например, NTFS, ext4) блокировка записи используется для предотвращения одновременного изменения файла несколькими процессами. Реализуется через системные вызовы (например, flock в Linux, LockFileEx в Windows). Блокировка может быть обязательной (mandatory) — операционная система принудительно блокирует доступ, или рекомендательной (advisory) — процессы должны добровольно проверять блокировку.
Примеры использования
- Банковские системы: при переводе средств блокировка записи на счёте предотвращает одновременное списание и зачисление, что могло бы привести к некорректному балансу.
- Системы бронирования: блокировка записи на билет или номер в гостинице гарантирует, что один и тот же ресурс не будет продан дважды.
- Редакторы кода с совместным доступом: блокировка записи на файл предотвращает конфликты при одновременном редактировании.
Интересные факты
- В СУБД, использующих MVCC, блокировка записи не блокирует чтение (читатели видят старую версию данных), что значительно повышает параллелизм.
- В распределённых системах (например, Apache Cassandra, Amazon DynamoDB) блокировки записи реализуются через консенсусные протоколы (Paxos, Raft) или механизмы «последняя запись побеждает» (last-write-wins).
- В некоторых базах данных (например, SQLite) блокировка записи может быть на уровне всей базы данных, что делает её непригодной для высоконагруженных многопользовательских приложений.
Источники
- Теория баз данных: учебник / К. Дж. Дейт. — М.: Вильямс, 2016.
- PostgreSQL Documentation: Chapter 13. Concurrency Control.
- MySQL 8.0 Reference Manual: InnoDB Locking.
- Microsoft SQL Server Documentation: Locking in the Database Engine.
- Oracle Database Concepts: Data Concurrency and Consistency.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →