Что такое Deadlock в базах данных и какие стратегии существуют для его предотвращения?
Deadlock (взаимная блокировка) в базах данных — это ситуация, при которой две или более транзакции бесконечно ожидают друг друга, удерживая ресурсы, которые нужны другой стороне. Ни одна из транзакций не может продолжить выполнение, пока другая не освободит нужный ресурс, что приводит к «мёртвой точке».
**Пример возникновения дедлока:**
— Транзакция A блокирует строку 1 и ожидает строку 2.
— Транзакция B блокирует строку 2 и ожидает строку 1.
Обе транзакции ждут друг друга бесконечно.
**Причины возникновения дедлоков:**
1. Конкурентный доступ к одним и тем же ресурсам.
2. Удержание блокировок на длительное время.
3. Непоследовательный порядок захвата ресурсов в разных транзакциях.
4. Использование эксклюзивных блокировок там, где достаточно разделяемых.
**Стратегии предотвращения дедлоков:**
1. **Упорядочивание ресурсов.** Все транзакции должны захватывать ресурсы (таблицы, строки) в одном и том же порядке. Это исключает циклические зависимости.
2. **Таймауты транзакций.** Устанавливается максимальное время ожидания блокировки. Если транзакция не может получить ресурс за отведённое время, она откатывается и повторяется позже.
3. **Обнаружение дедлоков (Detection).** СУБД периодически строит граф ожидания (Wait-for Graph) и ищет циклы. При обнаружении цикла одна из транзакций выбирается «жертвой» и откатывается. Этот подход используется в PostgreSQL, MySQL InnoDB и других.
4. **Минимизация времени удержания блокировок.** Транзакции должны быть как можно короче. Следует избегать пользовательского ввода внутри транзакции и выполнять только необходимые операции.
5. **Использование оптимистичной блокировки.** Вместо пессимистичных блокировок применяется версионирование данных (MVCC). Транзакция работает со снимком данных и проверяет конфликты только при коммите.
6. **Снижение уровня изоляции.** В ряде случаев допустимо снизить уровень изоляции (например, с SERIALIZABLE до READ COMMITTED), что уменьшает количество блокировок и вероятность дедлоков.
7. **Пакетная обработка вместо построчной.** Обновление большого количества строк одним запросом вместо цикла снижает число захватываемых блокировок.
8. **Индексирование.** Правильные индексы уменьшают количество строк, которые сканирует и блокирует транзакция, снижая вероятность пересечения с другими транзакциями.
**Обработка дедлоков в коде:**
Приложение должно уметь перехватывать ошибки дедлока (например, код 1213 в MySQL или класс 40P01 в PostgreSQL) и автоматически повторять транзакцию с экспоненциальной задержкой.
Правильное проектирование транзакций, грамотная индексация и мониторинг блокировок — ключевые инструменты для минимизации дедлоков в продакшн-системах.
