Ошибка 1213 Deadlock found в InnoDB означает конфликт блокировок: транзакции ждут ресурсы друг друга, и СУБД прерывает одну из них. После такого отката приложение должно заново выполнить всю транзакцию, включая чтение данных и проверки, а не только последний UPDATE.
Сначала подтвердите код ошибки и сохраните сведения о конфликте. Затем проверьте границы повтора: откат базы не отменяет уже отправленное письмо или запрос в платёжный сервис. Простое обновление страницы может повторить бизнес-действие.
1. Отличите deadlock от долгого ожидания
Найдите в журнале приложения код драйвера, SQLSTATE, время с часовым поясом и технический идентификатор запроса. HTTP 500 сам по себе не доказывает deadlock: нужна исходная ошибка БД.
- 1213, обычно SQLSTATE 40001: обнаружен deadlock; InnoDB откатывает выбранную транзакцию целиком.
- 1205, Lock wait timeout: истекло ожидание блокировки. По умолчанию может откатиться только текущий SQL-оператор; поведение зависит от настройки
innodb_rollback_on_timeout. - Обрыв соединения при COMMIT: результат может остаться неизвестным. Нельзя считать его подтверждённым откатом и запускать тот же обработчик без сверки.
Разница между откатом оператора и транзакции описана в документации MySQL. Для тайм-аута нужен отдельный обработчик с явным завершением текущей транзакции, а не продолжение частично выполненной работы.
2. Найдите обе стороны конфликта
Попросите администратора БД выполнить диагностическую команду вскоре после ошибки:
SHOW ENGINE INNODB STATUS;
В секции LATEST DETECTED DEADLOCK сопоставьте время события, участвующие транзакции, SQL, удерживаемые и ожидаемые блокировки, выбранную для отката транзакцию. Назначение этих полей приведено в справочнике MariaDB.
Это последний обнаруженный конфликт, а не история всех ошибок. Если его время не совпадает с инцидентом, вывод не подтверждает причину именно вашего сбоя. Для повторяющихся случаев администратор может временно включить innodb_print_all_deadlocks, обеспечить ротацию журнала и выключить расширенный сбор после диагностики.
Не передавайте полный вывод в публичный чат: SQL и записи блокировок могут содержать реальные значения. Для разбора оставьте структуру запросов, имена индексов, типы блокировок и порядок действий, удалив персональные данные и секреты. Связать событие с HTTP-запросом поможет поиск по request ID.
Пример: одинаковые строки, обратный порядок
Условный обработчик A сначала изменяет строку X, затем Y; обработчик B — сначала Y, затем X. Если каждый уже удерживает первую блокировку и ждёт вторую, возникает цикл ожидания.
Проверять нужно весь путь от начала транзакции, включая ранее выполненные запросы. Последний UPDATE в отчёте показывает место ожидания, но не обязательно действие, которое создало конфликт. Отдельно сравните обработчики сайта, фоновых задач и импорта: они могут менять одни таблицы в разном порядке.
3. Повторяйте транзакцию с ограничениями
Безопасный обработчик подтверждённого deadlock строится вокруг всей операции:
- Завершить обработку откатившейся попытки и привести соединение или объект транзакции в корректное состояние средствами драйвера либо ORM.
- Проверить лимит попыток и общий срок выполнения запроса.
- Сделать ограниченную паузу со случайным разбросом, уже не удерживая транзакцию.
- Начать новую транзакцию, заново прочитать данные и проверить бизнес-условия.
- Выполнить связанные изменения и COMMIT; сообщить об успехе только после подтверждения.
- При исчерпании лимита вернуть контролируемую ошибку и записать диагностическое событие.
Число попыток и задержки выбирают под допустимое время операции. Бесконечный повтор скрывает неисправность и наращивает нагрузку. Не добавляйте второй цикл, если повторами уже управляет фреймворк: сначала выясните его фактическое поведение.
Письмо, HTTP-вызов и изменение нетранзакционной таблицы не откатятся вместе с InnoDB. Если они входят в обработчик, сначала измените его границы: например, сохраняйте намерение отправки в транзакционной outbox-таблице, а доставку выполняйте отдельно с защитой от дублей. Неизвестный результат внешнего вызова разбирается по правилам повтора API после тайм-аута.
4. Уменьшите вероятность нового конфликта
Сравните порядок захвата строк и таблиц во всех конкурирующих обработчиках. Уберите сетевые ожидания из открытой транзакции, сократите её длительность и проверьте, позволяют ли индексы обращаться к нужным строкам без лишнего сканирования. Эти меры рекомендует руководство MySQL по deadlock.
Увеличение тайм-аута не исправляет цикл ожидания. Менять уровень изоляции или отключать обнаружение deadlock без проверки бизнес-инвариантов тоже не стоит: поведение блокировок изменится, но корректность операции сама собой не появится.
На изолированном стенде запустите конфликтующие операции параллельно. Проверьте не только отсутствие необработанной ошибки, но и итоговые данные: нет двойного изменения, потерянной записи или повторного уведомления; исчерпание лимита даёт ожидаемый отказ.
Когда нужен разбор приложения
Web-Puls помогает заметить внешнюю недоступность сайта, но HTTP-проверка не показывает блокировки InnoDB и не подтверждает корректность записи заказа. Для контроля исправления нужны журналы приложения, число откатов и повторов, длительность операций и проверка результата в БД.
Если конфликт повторяется и мешает работе сайта, отправьте заявку на диагностику: укажите затронутое действие, время, версию СУБД, код ошибки и обезличенную схему конкурирующих запросов. Формат и стоимость работ согласуются до начала; пароли и полный дамп базы в заявку не нужны.