Ответ
Да, сталкивался с анализом и предотвращением deadlock-ов, в основном в SQL Server.
Что такое deadlock? Это ситуация, когда две или более транзакции взаимно блокируют ресурсы (например, строки в таблицах), которые нужны каждой из них для завершения. Ни одна не может продолжить работу, ожидая освобождения ресурса, заблокированного другой. СУБД обнаруживает это и сама "разруливает" конфликт, выбирая одну транзакцию как "жертву" (victim), откатывая её и завершая с ошибкой 1205.
Пример кода с обработкой deadlock на стороне приложения (C#):
int retryCount = 3;
while (retryCount > 0)
{
try
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
using (var connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
// ... логика с несколькими командами, обновляющими данные ...
scope.Complete(); // Фиксация транзакции
break; // Успех, выходим из цикла
}
}
catch (SqlException ex) when (ex.Number == 1205) // Код ошибки deadlock
{
retryCount--;
if (retryCount == 0) throw; // Превышены попытки
await Task.Delay(100); // Небольшая задержка перед повторной попыткой
// Логируем ошибку для последующего анализа
_logger.LogWarning(ex, "Обнаружен deadlock, повторная попытка {Retry}", 3 - retryCount);
}
}
Стратегии предотвращения (на уровне БД и кода):
- Единый порядок блокировок: Всегда запрашивать блокировки ресурсов (таблиц, строк) в одинаковом порядке во всем приложении.
- Короткие транзакции: Выполнять в транзакции только необходимую логику, избегать долгих операций или вызовов внешних сервисов.
- Изоляция
READ COMMITTED SNAPSHOT: Включение этого уровня изоляции на уровне БД может сильно снизить количество блокировок при чтении. - Индексы: Оптимизированные индексы уменьшают время сканирования таблиц и, следовательно, время удержания блокировок.
- NOLOCK / READ UNCOMMITTED: Использовать с осторожностью (допускает "грязное" чтение) только для отчетов, где абсолютная консистентность не критична.
- Мониторинг: Использовать расширенные события SQL Server (
system_healthсессия) или запросы кsys.dm_tran_locksдля анализа причин deadlock.