#Что означает неисправность и в каких условиях возникает
Ошибка ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction появляется, когда две транзакции захватывают блокировки в разном порядке. Здесь разобран именно конфликт конкурентных UPDATE в InnoDB, а не любой сбой SQL. InnoDB выбирает одну транзакцию жертвой и откатывает её; приложение должно повторить всю транзакцию с ограниченным числом попыток, а порядок доступа к строкам следует сделать согласованным.
#Возможные причины: как различить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Разный порядок изменения строкОдин запрос изменяет строку A, затем B, второй — B, затем A. | В LATEST DETECTED DEADLOCK обе транзакции ждут блокировку друг друга. | Обновлять строки в устойчивом порядке ID. |
| Длительные транзакцииПриложение удерживает блокировки во время сетевых вызовов и вычислений. | Большие значения времени, много запросов между BEGIN и COMMIT. | Сократить транзакцию и выполнять внешнюю работу до BEGIN. |
| Неудачные условия WHERE и индексыUPDATE сканирует гораздо больше строк, чем предполагалось. | EXPLAIN показывает широкий скан и неудачный индекс. | Проверить выборку на копии и нужный индекс. |
#Пошаговая диагностика и устранение
- Сохраните полный код ошибкиВ журнале сайта найдите ERROR 1213 и время, идентификатор операции, имя таблицы; проверьте, что используется InnoDB и ошибка именно 1213, а не 1205 Lock wait timeout. Не публикуйте значения запросов, содержащие персональные данные или пароли; для воспроизведения создайте синтетические записи.
- Откройте две независимые сессии для примераНа тестовой базе откройте два терминала и в каждом запустите
mysql -u test_user -p -h 127.0.0.1 test_db, подставив реальные тестовые учётные данные. В первой консоли выполните BEGIN и обновите запись с ID 1, во второй BEGIN и запись ID 2, затем наоборот; одна из операций будет ждать, а после второго конкурирующего UPDATE возможно возникновение 1213. Не повторяйте этот эксперимент на рабочей таблице. - Прочитайте отчёт InnoDB о последнем конфликтеПод административным SQL-доступом выполните
SHOW ENGINE INNODB STATUS\Gв клиенте mysql: символ\Gвыводит вертикальный отчёт. Найдите разделLATEST DETECTED DEADLOCKс операциями, таблицами, индексами и выбранной жертвой; он хранит только последний конфликт и может быть перезаписан новым событием. Скопируйте фрагмент без личных данных в служебный журнал. - Сопоставьте порядок запросов в кодеОткройте сервисный обработчик, где начинается транзакция; найдите BEGIN, UPDATE и COMMIT/ROLLBACK. Составьте порядок блокировки строк в двух конкурирующих запросах. Если один обновляет id=1 затем id=2, а второй наоборот, согласуйте порядок по возрастанию id; при нескольких таблицах также придерживайтесь одинаковой очередности.
- Уменьшите срок удержания блокировокВынесите из транзакции длительные сетевые обращения, отправку почты и генерацию отчётов. Не удаляйте проверки целостности, не делайте многократный COMMIT ради исчезновения ошибки. Если транзакция должна быть атомарной, сокращайте время внутри BEGIN–COMMIT, сохраняя все необходимые проверки и изменения вместе.
- Добавьте правильный повтор всей транзакцииПосле 1213 выполните ROLLBACK, если ещё требуется, откройте новую транзакцию и повторите последовательность операций целиком, предварительно заново прочитав изменившиеся данные. Ограничьте число попыток, делайте небольшую случайную задержку и не повторяйте внешнее действие вроде списания денег без защиты от повторного выполнения. Повтор одного UPDATE вместо всей операции часто некорректен.
- Проверьте план запросов и индексНа тестовой копии для SELECT с тем же WHERE выполните EXPLAIN; убедитесь, что условие поиска использует ожидаемый индекс и не читает большинство строк. Добавление индекса делайте после проверки плана и стоимости изменения структуры, с резервной копией. Без проверки не ставьте FORCE INDEX и не отключайте обнаружение взаимных блокировок.
- Повторите безопасный конкурентный тестНа тестовых строках одновременно выполните два запросa в обратном порядке после правки, убедитесь, что оба заканчиваются либо один корректно повторяется. Просмотрите журнал исключений: после ограниченного повтора нет необработанных 1213, данные согласованы и ни один заказ не применён дважды. Если конфликт остаётся, запишите новую пару транзакций из отчёта InnoDB и пересмотрите структуру операций.
- Команды для отдельных ситуацийВыберите только подходящий вариант. Это не одна последовательность: часть команд диагностирует проблему, а часть меняет настройки или данные.
#Как проверить исправление и что делать, если оно не помогло
Проверяйте не только отсутствие сообщений 1213, но и правильные итоговые значения, соответствие количества списаний/операций и журналы повторных попыток. Если проблема появляется только под нагрузкой, соберите тексты обеих транзакций и планы EXPLAIN без персональных данных; воспроизводите на копии.