Как избежать deadlock при переводах
Вопрос
Два параллельных перевода: A→B и B→A. Каждая транзакция делает UPDATE баланса отправителя, потом получателя, и иногда ловит deadlock. Какое исправление правильное?
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Варианты ответа
- Поднять уровень изоляции до Serializable для обеих транзакций
- Увеличить
deadlock_timeout, чтобы транзакции дождались друг друга - Перейти на Read Uncommitted, чтобы транзакции не блокировали друг друга
- Блокировать строки в одном порядке:
... ORDER BY id FOR UPDATEправильный ответ
Разбор
Deadlock возникает, когда транзакции берут одни и те же блокировки в разном порядке: первая держит A и ждёт B, вторая держит B и ждёт A. Если все берут блокировки в едином порядке, цикл ожидания невозможен. deadlock_timeout (по умолчанию 1 с) это лишь время ожидания до запуска проверки на взаимоблокировку; его увеличение только отложит ошибку. Serializable не убирает блокировки строк при UPDATE и добавляет ошибки сериализации. Read Uncommitted в PostgreSQL работает как Read Committed, а блокировки записи от уровня изоляции не зависят. Повтор транзакции при ошибке 40P01 всё равно стоит иметь.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
Advisory-блокировки в PostgreSQL
Следующий вопрос
Взаимоблокировки: как ловить и предотвращать
Термины по теме
Ещё по теме «Транзакции и изоляция»
- Долгая транзакция и раздувание таблиц
- MVCC и VACUUM в PostgreSQL
- VACUUM или VACUUM FULL на проде
- Зачем нужна заморозка и что такое wraparound
- Что делает PostgreSQL при deadlock
- Уровень изоляции по умолчанию в PostgreSQL
- Как обеспечивается Durability
- ACID