Ответ
Блокировки обеспечивают согласованность данных в многопользовательской среде. Существует две фундаментальные стратегии.
1. Оптимистичная блокировка (Optimistic Locking)
Предпосылка: Конфликты при одновременном изменении данных редки. Проверка конфликта происходит в момент коммита транзакции. Реализация: Через поле версии или временной метки.
-
JPA/Hibernate пример:
@Entity public class Account { @Id private Long id; private BigDecimal balance; @Version // Специальное поле для оптимистичной блокировки private Long version; }Механизм: При чтении объекта фиксируется его
version. При обновлении в запросеUPDATEдобавляется условиеWHERE id=? AND version=?. Если версия изменилась (другой поток уже обновил запись), количество обновлённых строк будет 0, и JPA выброситOptimisticLockException. Плюсы: Высокая производительность, нет долгих блокировок. Минусы: Частые конфликты приводят к большому числу откатов.
2. Пессимистичная блокировка (Pessimistic Locking)
Предпосылка: Конфликты вероятны. Данные блокируются на время транзакции. Реализация в JPA:
// Блокировка при чтении (обычно SELECT ... FOR UPDATE)
Account account = entityManager.find(
Account.class,
accountId,
LockModeType.PESSIMISTIC_WRITE
);
// Или явная блокировка позже
entityManager.lock(account, LockModeType.PESSIMISTIC_WRITE);
Типы пессимистичных блокировок в JPA:
PESSIMISTIC_READ: Разделяемая блокировка (shared lock). Другие транзакции могут читать, но не изменять данные.PESSIMISTIC_WRITE: Эксклюзивная блокировка (exclusive lock,FOR UPDATE). Другие транзакции не могут ни читать, ни изменять данные (зависит от СУБД).PESSIMISTIC_FORCE_INCREMENT: Блокировка с одновременным увеличением поля@Version.
Плюсы: Гарантирует целостность, предотвращает конфликты. Минусы: Риск взаимоблокировок (deadlock) и снижение производительности из-за ожиданий.
Уровни блокировок в СУБД
- Блокировка строк (Row-level lock): Блокируется только изменяемая строка. Наиболее гранулярный и предпочтительный уровень.
- Блокировка страниц (Page-level lock): Блокируется страница данных (группа строк).
- Блокировка таблиц (Table-level lock): Блокируется вся таблица. Сильно снижает параллелизм, используется для DDL-операций или массовых обновлений.
Выбор стратегии: Используйте оптимистичную блокировку для сценариев с высокой конкуренцией на чтение и низкой — на запись. Пессимистичную — для критичных данных, где конфликт при одновременном изменении недопустим (например, финансовые операции).
Ответ 18+ 🔞
А, слушай, про блокировки в базах, да? Ну это, блядь, целая опера, если честно. Два главных подхода, как не наебнуться с данными, когда их двадцать пять программистов одновременно трогают.
1. Оптимистичная блокировка (Optimistic Locking)
Суть её в чём: Мы делаем вид, что все вокруг — адекватные люди и редко когда лезут в одну и ту же запись одновременно. То есть, работаем спокойно, а проверяем, не обосрались ли мы, только в самый последний момент, когда сохраняем. Как это выглядит технически: Заводим специальное поле — версию или timestamp.
-
Вот как в Hibernate это, сука, делается:
@Entity public class Account { @Id private Long id; private BigDecimal balance; @Version // Вот эта вот волшебная хуйня! private Long version; }Как работает этот фокус: Читаешь ты запись, запоминаешь её
version. Потом, когда пишешь её обратно, в апдейте добавляется хитрая проверка:WHERE id=? AND version=?. И если за это время какой-то другой мудак уже успел её обновить и версию увеличить — твой апдейт нихуя не сработает (ноль строк обновится), и тебе выкинутOptimisticLockException. Всё, иди нахуй, начинай заново. Плюсы: Быстро, блядь, не вешаем замки на всё подряд. Минусы: Если конфликты реально частые, то ты будешь только и делать, что ловить эти ебучие исключения и переделывать работу. Пиздец, а не жизнь.
2. Пессимистичная блокировка (Pessimistic Locking)
А вот это уже серьёзно: Здесь мы исходим из того, что все вокруг — ебучие хамы и обязательно полезут в наши данные. Поэтому мы сразу, как только посмотрели на запись, кричим: "Моё! Не трогай, сука!" и вешаем на неё замок. Делается это в JPA так:
// Берём запись и сразу же блокируем её на запись (это типа SELECT ... FOR UPDATE)
Account account = entityManager.find(
Account.class,
accountId,
LockModeType.PESSIMISTIC_WRITE
);
// Или можно потом припереться и залочить
entityManager.lock(account, LockModeType.PESSIMISTIC_WRITE);
Какие бывают замки:
PESSIMISTIC_READ: Замок "только посмотреть". Другие могут тоже читать, но хуй кто что изменит.PESSIMISTIC_WRITE: Полный, блядь, эксклюзив.FOR UPDATEв чистом виде. Ни читать, ни писать, пока я не отпущу. В общем, иди нахуй.PESSIMISTIC_FORCE_INCREMENT: Комбо-удар: и замок повесил, и версию увеличил, на всякий случай.
Плюсы: Полная, блядь, гарантия, что пока ты работаешь, никто тебе в тарелку не плюнет. Минусы: Риск дедлоков (когда два мудака повисли друг на друге и ждут), и производительность может просесть, потому что все стоят в очереди.
А ещё замки бывают разного калибра, ёпта:
- На строку (Row-level lock): Идеально. Блокируем только ту строчку, которую трогаем. Все довольны.
- На страницу (Page-level lock): Уже хуже. Блокируется кусок данных, где несколько строк. Может зря кого-то зацепить.
- На всю таблицу (Table-level lock): Ну это пиздец полный. Вешаем амбарный замок на всю таблицу. Используется, когда надо что-то глобально поменять, а в обычной жизни — терпения ебать ноль, если так делать.
Так что же выбрать, спросишь ты? Если у тебя народ в основном читает, а пишет редко — оптимистичная, и не еби мозг. Если же у тебя, например, финансовый перевод и два человека пытаются списать деньги с одного счета — тут без вариантов, пессимистичная, и пусть все ждут своей очереди, как в советской поликлинике.