Ответ
Deadlock (взаимная блокировка) — это ситуация в многопользовательской СУБД, когда две или более транзакции бесконечно ожидают друг друга, потому что каждая удерживает блокировку на ресурсе, который требуется другой.
Классический пример:
-- ТРАНЗАКЦИЯ A
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- Блокирует запись id=1
-- Транзакция A ждет блокировки на id=2...
-- ТРАНЗАКЦИЯ B (выполняется параллельно)
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE id = 2; -- Блокирует запись id=2
-- Транзакция B ждет блокировки на id=1...
-- Теперь A ждет B, а B ждет A. Deadlock!
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- Транзакция A (ждет)
UPDATE accounts SET balance = balance + 50 WHERE id = 1; -- Транзакция B (ждет)
Как СУБД решает проблему? Большинство СУБД (SQL Server, PostgreSQL, Oracle) имеют детектор взаимных блокировок, который периодически проверяет систему на наличие циклических зависимостей. При обнаружении deadlock:
- СУБД выбирает одну транзакцию в качестве "жертвы" (обычно ту, которую дешевле откатить).
- Завершает её с ошибкой (например,
ERROR 1213 (40001): Deadlock foundв MySQL). - Все изменения "жертвы" откатываются, и её блокировки снимаются.
- Другие транзакции в deadlock могут продолжить выполнение.
Как предотвращать deadlock на практике?
- Унифицированный порядок доступа: Всегда блокируйте ресурсы (например, строки таблиц) в одном и том же порядке во всех транзакциях. В примере выше, если бы обе транзакции сначала обновляли
id=1, а потомid=2, deadlock бы не возник. - Короткие транзакции: Выполняйте как можно меньше операций в одной транзакции и завершайте её быстро.
- Использование таймаутов: Установите
SET LOCK_TIMEOUT 5000;(5 секунд). Если транзакция не может получить блокировку за это время, она прервется, не дожидаясь deadlock. - Изоляция
READ COMMITTED SNAPSHOT(в SQL Server) илиREPEATABLE READ(в некоторых СУБД): Эти уровни изоляции могут уменьшить количество блокировок, используя управление версиями строк. - Тщательный дизайн индексов: Отсутствие подходящего индекса может привести к блокировке всей таблицы вместо одной строки, увеличивая вероятность deadlock.
Ответ 18+ 🔞
Давай разжую про эти ваши дедлоки, а то у меня от этой темы уже волнение ебать какое-то. Представь себе, сидят два чувака в базе данных, оба в транзакциях, и оба ждут друг от друга хуй знает чего. Это и есть deadlock, или, по-нашему, взаимная блокировка. Ситуация, блядь, классическая: каждый держит в заложниках то, что нужно другому, и оба уперлись, как бараны.
Вот смотри, живой пример, чтобы ты сам от себя охуел от наглядности:
-- ЧУВАК А
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- Он прихватил запись с id=1
-- И теперь сидит, бздит, ждёт, когда ему отдадут id=2...
-- ЧУВАК Б (делает всё параллельно, умник)
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE id = 2; -- А этот, хитрая жопа, уже схватил id=2
-- И тоже уставился в потолок, мечтая о id=1...
-- И всё, приехали. А ждёт Б, Б ждёт А. Ёперный театр, полный тупик!
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- Чувак А (висит в ожидании)
UPDATE accounts SET balance = balance + 50 WHERE id = 1; -- Чувак Б (тоже повис)
И что, теперь они так до скончания веков будут? Да хуй там! Умные дядьки, которые эти СУБД писали, не лыком шиты. У них там есть специальный стукач, детектор дедлоков. Он, сука, как надзиратель, ходит и смотрит, не образовалась ли где порочная петля из транзакций. Как находит — сразу начинается разборка.
- Он выбирает одного пацана на роль "козла отпущения" — обычно того, кого проще и дешевле откатить.
- Бах — и выкидывает ему ошибку, типа "Deadlock found, иди на хуй".
- Всё, что этот бедолага натворил, откатывается к хуям, и все его блокировки снимаются.
- Второй чувак, довольный такой, получает наконец то, что хотел, и спокойно продолжает работу. Жестоко, но справедливо.
Как не попасть в такую жепень? Слушай сюда, э бошка думай, запоминай правила выживания:
- Порядок — всё! Всегда лезь к данным в одном и том же порядке. В нашем примере, если бы оба чувака сначала хватали
id=1, а потом ужеid=2, никакой бы драки не было. Один бы взял, сделал дело, отпустил, потом второй. А так — мудя получилась. - Не размазывай сопли. Делай транзакции короткими и яростными. Залетел, быстро сделал что нужно, и вышел. Не надо там чаи гонять и полбазы блокировать.
- Ставь таймер. Можно сказать системе: "Слушай, если я больше 5 секунд жду — бросай это дело". Команда типа
SET LOCK_TIMEOUT 5000;. Лучше уйти с позором, чем висеть вечность. - Играй настройками. Некоторые уровни изоляции (типа
READ COMMITTED SNAPSHOT) меньше блокируют друг друга, используя хитрые версии данных. Но тут, чувак, надо понимать, что делаешь, а то будет тебе хиросима. - Индексы, блядь, расставь! Это самое важное. Если нет нормального индекса, то чтобы одну строку обновить, система может заблокировать всю таблицу целиком. А когда ты всю таблицу лочишь, вероятность, что кто-то врежется в тебя и получится дедлок — овердохуища. Так что следи за хозяйством, не будь распиздяем.