Взаимоблокировка InnoDB: повторяем транзакцию целиком
Что делать при deadlock в InnoDB, как повторить транзакцию и почему нельзя бездумно повторять любой запрос.
- Конфликт блокировокInnoDB откатывает одну транзакцию
- Ограниченный повторЗаново выполняем всю транзакцию
- ИтогПодтверждаем успех или возвращаем ошибку
Две транзакции заняли нужные друг другу строки и ждут освобождения блокировок. InnoDB обнаруживает этот круг и откатывает одну из транзакций. Такая взаимоблокировка возможна и в исправном приложении. Важно правильно обработать отказ: повторить всю операцию с ограниченным числом попыток, а не бесконечно запускать последний UPDATE.
Сначала получаем свидетельство
SHOW ENGINE INNODB STATUS;В диагностическом выводе ищите сведения о последней взаимоблокировке. Он может содержать текст запросов и значения, поэтому не публикуйте его целиком. При частых событиях предусмотренный сервером журнал помогает сохранить больше случаев, чем один последний снимок.
Когда и сколько раз повторять транзакцию
# Псевдокод, а не готовый драйверный API:
for attempt in range(3):
try:
begin()
update_rows_in_consistent_order()
commit()
break
except Deadlock:
rollback_if_needed()
if attempt == 2:
raise
wait_with_jitter(attempt)Повторяется вся логическая транзакция с её проверками, а не только последний UPDATE. Классифицируйте ошибку средствами драйвера; не повторяйте подряд любое исключение. Ограничение числа попыток и небольшой разброс задержки уменьшают вероятность, что конкуренты снова встретятся одновременно.
Внешние действия требуют отдельного решения. Если внутри попытки уже отправлено письмо или списаны средства через другой сервис, откат SQL не отменит этот эффект. Используйте согласованный механизм идемпотентности или вынесенную доставку события. Это проверяется отдельно от обработки deadlock.
Снижаем вероятность конфликта
Обновляйте общие объекты в одинаковом порядке, держите транзакции короткими и проверьте индексы фильтров. Транзакция не должна ждать пользователя или длительный сетевой вызов. При этом уменьшение числа конфликтов не отменяет обработку редкого повторения.
Проверять повтор удобнее двумя одновременными операциями с общими строками. Убедитесь, что после deadlock данные остаются правильными, попытка повторяется и видна в журнале. Если лимит попыток исчерпан, приложение должно вернуть понятную ошибку, а не зависнуть или скрыть отказ.
