Вступить в клуб →
сложнаявопросSQL и оптимизация запросов

Deadlock при параллельном переводе бонусов между счетами

Перевод бонусов между счетами выполняется двумя UPDATE внутри одной транзакции. Два параллельных перевода задевают одни и те же две строки, но идут по ним в разном порядке:

-- транзакция A (перевод 1 -> 2)
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- транзакция B (перевод 2 -> 1)
UPDATE accounts SET balance = balance - 100 WHERE id = 2;
UPDATE accounts SET balance = balance + 100 WHERE id = 1;

В логах регулярно появляется Deadlock found when trying to get lock; try restarting transaction. Что здесь верно?

  • Взаимная блокировка возможна только при явном LOCK TABLES: обычные UPDATE внутри транзакции строчных блокировок не ставят, поэтому причину надо искать в настройках соединения
  • Ошибка означает, что СУБД не хватило памяти под структуру блокировок; помогает увеличение буферного пула и оперативной памяти на сервере базы
  • Достаточно повысить уровень изоляции до SERIALIZABLE: на нём транзакции выстраиваются в очередь и взаимные блокировки не возникают в принципе
  • Транзакции захватывают одни и те же строки в противоположном порядке и ждут друг друга; СУБД снимает одну из них. Лечится единым порядком обновления строк и повтором отменённой транзакции

🔒 Проверка ответа — для участников клуба

  • Проверка ответа
  • Подсказка, если застряли
  • Разбор с объяснением, почему так
  • Прогресс по всем задачам и виртуальные собеседования
Зарегистрироваться →

Регистрация занимает минуту

Другие задачи раздела