Ответ
Блокировки — это фундаментальный механизм в транзакционных базах данных (таких как PostgreSQL, MySQL), который обеспечивает целостность данных (изоляцию транзакций). Их можно классифицировать по нескольким критериям.
1. По уровню гранулярности (что блокируем):
- Блокировка таблицы (Table Lock): Блокируется вся таблица. Самый низкий уровень параллелизма, но и самые низкие накладные расходы на управление блокировками.
- Блокировка страницы (Page Lock): Блокируется страница данных (блок на диске, содержащий несколько строк).
- Блокировка строки (Row Lock): Блокируется одна или несколько строк. Обеспечивает наивысший уровень параллелизма, но требует больше ресурсов для управления.
2. По режиму доступа (как блокируем):
-
Разделяемая (Shared Lock, S-lock):
- Назначение: Для чтения данных.
- Правило: Несколько транзакций могут одновременно удерживать S-lock на одном и том же ресурсе. Это позволяет им параллельно читать данные.
- Конфликт: Блокирует установку эксклюзивной блокировки (X-lock). Пока есть хоть одна S-lock, никто не может изменить данные.
- SQL-пример (PostgreSQL/MySQL):
SELECT ... FOR SHARE(илиLOCK IN SHARE MODEв MySQL).
-
Эксклюзивная (Exclusive Lock, X-lock):
- Назначение: Для изменения или удаления данных (UPDATE, DELETE).
- Правило: Только одна транзакция может удерживать X-lock на ресурсе.
- Конфликт: Блокирует установку любых других блокировок (и S-lock, и X-lock). Никто не может ни читать, ни изменять данные, пока X-lock не будет снята.
- SQL-пример (PostgreSQL/MySQL):
SELECT ... FOR UPDATE.
3. По стратегии получения блокировки:
Это не типы блокировок как таковые, а подходы к их использованию на уровне приложения.
-
Пессимистичная блокировка (Pessimistic Locking):
- Идея: «Предполагаем, что конфликт вероятен». Блокировка ресурса происходит до выполнения операции, чтобы предотвратить конфликты.
- Реализация: Используются явные S-lock или X-lock (
FOR UPDATE/FOR SHARE). Транзакция захватывает ресурс и держит его до своего завершения (COMMIT/ROLLBACK). - Пример:
BEGIN; -- Блокируем строку от изменений другими транзакциями SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- Безопасно обновляем баланс UPDATE accounts SET balance = balance - 100 WHERE id = 1; COMMIT;
-
Оптимистичная блокировка (Optimistic Locking):
- Идея: «Предполагаем, что конфликты маловероятны». Блокировка не используется. Вместо этого перед обновлением проверяется, не изменились ли данные с момента их чтения.
- Реализация: Обычно используется поле
versionилиupdated_atв таблице. -
**Пример (логика на уровне приложения):
-- 1. Читаем запись вместе с ее версией SELECT balance, version FROM accounts WHERE id = 1; -- (Приложение получает balance=1000, version=5) -- 2. Приложение выполняет логику... -- 3. Пытаемся обновить, проверяя, что версия не изменилась UPDATE accounts SET balance = 900, version = 6 -- Увеличиваем версию WHERE id = 1 AND version = 5; -- Условие на старую версиюЕсли
UPDATEзатронул 0 строк, значит, другая транзакция уже изменила данные. В этом случае операцию нужно повторить (прочитать данные заново и попробовать снова).
-
Рекомендательные блокировки (Advisory Locks):
- Описание: Это блокировки, управляемые приложением, которые не привязаны к таблицам или строкам. Они представляют собой просто блокировку по строковому или числовому ключу. Полезны для синхронизации фоновых задач или выполнения операций, которые не связаны с конкретной строкой в БД.
Ответ 18+ 🔞
А, ну вот, подошли к самому скучному, но охуенно важному делу — блокировкам в базах данных. Это как в коммуналке: если все одновременно полезут в холодильник, кто-то обязательно останется без сметаны, а кто-то с кастрюлей на голове. Чтобы такого пиздеца не было, придумали вот эту всю хуйню.
1. Что конкретно запираем нахуй? (Уровень гранулярности)
Тут всё просто, как три копейки. Можно заблокировать:
- Всю таблицу целиком (Table Lock): Самый тупой и грубый способ. Как будто на весь подъезд один замок повесил. Зато дешёвый для системы — не надо мозги напрягать, что там внутри творится.
- Страницу (Page Lock): Это уже потоньше. Страница — это кусок данных на диске, где строк несколько лежит. Запираешь как бы комнату в общежитии.
- Конкретную строку (Row Lock): Вот это уже высший пилотаж, ювелирная работа. Блокируешь ровно ту запись, с которой работаешь. Овердохуища параллелизма, но и возни с управлением этими замками — как с тараканами в хрущёвке.
2. А как именно запираем? (Режим доступа)
Тут два основных фокуса:
-
Разделяемая блокировка (Shared Lock, S-lock): Для чтения. Представь, что ты в библиотеке. Книгу (строку) могут одновременно читать несколько человек, но вырывать из неё страницы или писать в ней хуйню — нельзя. Пока хоть один читает, писателю — жопа.
- На SQL:
SELECT ... FOR SHARE(или в MySQLLOCK IN SHARE MODE).
- На SQL:
-
Эксклюзивная блокировка (Exclusive Lock, X-lock): Для записи, обновления, удаления. Это когда ты заваливаешься в сортир, щёлкнув защёлкой. Только ты один и можешь там наводить красоту. Никто другой ни зайти, ни даже в замочную скважину посмотреть не сможет, пока ты не вылезешь.
- На SQL:
SELECT ... FOR UPDATE. Классика дляUPDATEиDELETE.
- На SQL:
3. Стратегия: параноик или пофигист?
А вот это уже философия, блядь. Как ты подходишь к жизни.
-
Пессимистичная блокировка (Pessimistic Locking): Стратегия параноика. «Все вокруг мудаки, сейчас нахуйарят». Поэтому ты сначала хватаешь ресурс в ежовые рукавицы, а потом с ним работаешь.
BEGIN; -- Всё, строка в захвате. Никто, блядь, даже близко. SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- Теперь можно спокойно снимать бабки, не боясь, что их уже сняли. UPDATE accounts SET balance = balance - 100 WHERE id = 1; COMMIT;Минус: если долго думаешь, все остальные ждут, как лохи.
-
Оптимистичная блокировка (Optimistic Locking): Стратегия пофигиста. «Да ладно, пронесёт». Работаешь с данными без блокировок. Но перед тем как записать результат, проверяешь: «А не накосячил ли кто-то уже без меня?». Обычно для этого в таблице есть поле
version(версия) илиupdated_at(время обновления).-- 1. Читаем запись. Видим: balance=1000, version=5. SELECT balance, version FROM accounts WHERE id = 1; -- 2. В приложении решаем снять 100... -- 3. Пытаемся обновить, но ТОЛЬКО если версия та же! UPDATE accounts SET balance = 900, version = 6 -- Версию увеличиваем WHERE id = 1 AND version = 5; -- Вот это — магическое условиеЕсли после этого
UPDATEвернул 0 строк — всё, пиздец, кто-то успел раньше. Данные устарели, надо начинать сначала. Волнение ебать, но зато в обычных ситуациях — летает. -
Рекомендательные блокировки (Advisory Locks): А это вообще отдельная песня. Это как взять и повесить свой собственный амбарный замок на что угодно, хоть на дерево во дворе. Не привязаны к таблицам, просто синхронизируют логику приложения. Хочешь, чтобы два скрипта-демона не наступили друг другу на хвост — используй advisory lock. Удобная хуйня, когда нужно координировать что-то поверх БД.