Два участника могут ждать друг друга так, что никто не продолжит работу. Разбираем цикл ожиданий, отмену транзакции и отличие от обычной очереди.
Когда ожидание перестаёт быть очередью
Два сотрудника одновременно меняют складские сведения. Иногда одному нужно подождать, пока другой закончит работу с нужной записью. Такая пауза может быть нормальной. Проблема возникает, когда каждый уже удерживает то, что необходимо второму, и одновременно ждёт освобождения другого объекта.
Это взаимная блокировка, или deadlock: замкнутый круг ожиданий. В нём могут участвовать двое или больше. Для понимания важен именно круг, а не просто большое время ответа. Долгое ожидание без такого круга может иметь другую причину и потребовать другого разбора. Поэтому сообщение об ошибке стоит прочитать целиком, прежде чем делать вывод.
Условный пример двух товарных карточек
Представим две карточки: тетради и ручки. Первый сотрудник начал согласованное изменение обеих и получил возможность менять карточку тетрадей. Второй начал другую такую работу с карточки ручек. Затем первому понадобились ручки, а второму — тетради. Каждый ждёт объект, занятый другим, и удерживает свой до завершения общей работы.
В примере два участника и два объекта. Он специально упрощён, чтобы показать зависимость. Если бы второй сотрудник просто ждал тетради, не удерживая нужный первому объект, круга не было бы. После завершения первого участника очередь могла бы продолжиться. Именно эта разница отделяет обычное ожидание от взаимной блокировки.
Почему система выбирает отмену
Транзакция объединяет связанные изменения в одно целое: они должны сохраниться вместе либо быть отменены. Такая отмена позволяет освободить удерживаемые объекты и разорвать круг. В PostgreSQL взаимные блокировки обнаруживаются автоматически, после чего система прерывает одну из участвующих транзакций. Рассчитывать заранее на конкретного выбранного участника нельзя.
Следовательно, сообщение об отмене не обязательно означает поломку базы. Оно может означать срабатывание механизма разрешения конфликта. При этом отдельная операция приложения действительно не завершилась успешно. Пользователю важно получить понятный результат, а разработчику — обработать ситуацию, вместо того чтобы показывать успешное сохранение там, где его не произошло.
Что значит повторить работу корректно
Если транзакция отменена, нельзя считать, что все её предыдущие изменения уже сохранены. Руководство PostgreSQL объясняет принцип общей фиксации и отмены группы изменений. Поэтому повтор рассматривают для целой транзакции, сохраняя её исходный смысл. Продолжение только с последнего неудачного действия может нарушить задуманный порядок.
Документация MySQL рекомендует готовить приложение к повторному выполнению транзакции после такого конфликта. Это обязанность приложения и его разработчиков. Из этой рекомендации не следует, что человеку стоит многократно нажимать кнопку: интерфейс должен сам объяснять состояние и не создавать неопределённость для пользователя.
Как уменьшить вероятность круга
В учебном примере оба участника могут договориться обращаться к карточкам в одинаковом порядке: сначала тетради, затем ручки. Тогда не возникает описанной ситуации, где каждый начал с противоположного объекта. Общий порядок обращения — одна из рекомендаций документации PostgreSQL и MySQL.
MySQL также советует делать транзакции короткими и подбирать индексы, чтобы поиск затрагивал меньше записей. Индекс здесь можно представить как указатель для более точного поиска. Это направления для проверки специалистом, а не обещание убрать все задержки. Конкретные причины зависят от того, какие действия приложение выполняет вместе и какие объекты оно при этом удерживает.
Что передать специалисту
Полезное описание содержит время ошибки, действие пользователя и точный текст сообщения. Если известно, что параллельно выполнялась другая работа с теми же сведениями, добавьте это наблюдение. Не нужно самостоятельно удалять записи или останавливать чужую работу только на основании медленного экрана.
При разборе стоит разделить три вопроса: был ли обнаружен круг ожиданий, какая транзакция отменена и получил ли пользователь корректный ответ. Затем можно изучать порядок обращения к объектам и условия повтора. Такой порядок обсуждения помогает связать поведение базы с результатом для человека, даже если он пока не знаком с языком запросов.
Как перейти к практике
На курсе «SQL инженер» можно знакомиться с устройством работы с данными последовательно. Для понимания блокировок важно сначала разобраться, какие изменения должны сохраняться вместе и почему одновременная работа требует согласования.


