Как поймать SqlException, вызванный мертвой блокировкой?

От.NET 3.5 / приложение C#, я хотел бы поймать SqlException но только если это вызывается мертвыми блокировками на экземпляре SQL Server 2008 года.

Типичное сообщение об ошибке Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Все же это, кажется, не зарегистрированный код ошибки для этого исключения.

Фильтрация исключения против присутствия ключевого слова мертвой блокировки в их сообщении кажется очень ужасным способом достигнуть этого поведения. Кто-то знает правильный способ сделать это?

88
задан AdaTheDev 13 February 2010 в 08:32
поделиться

2 ответа

Код ошибки Microsoft SQL Server для тупиковой ситуации - 1205, поэтому вам нужно обработать SqlException и проверить его. Так, например, если для всех других типов SqlException вы хотите, чтобы исключение всплыло вверх:

catch (SqlException ex)
{
    if (ex.Number == 1205)
    {
        // Deadlock 
    }
    else
        throw;
}

Или, используя фильтрацию исключений, доступную в C # 6

catch (SqlException ex) when (ex.Number == 1205)
{
    // Deadlock 
}

Удобная вещь, которую нужно сделать, чтобы найти фактический код ошибки SQL для данного сообщения, - это посмотреть в sys.messages в SQL Server.

например.

SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033

Альтернативный способ обработки взаимоблокировок (из SQL Server 2005 и выше) - это делать это внутри хранимой процедуры с помощью поддержки TRY ... CATCH:

BEGIN TRY
    -- some sql statements
END TRY
BEGIN CATCH
    IF (ERROR_NUMBER() = 1205)
        -- is a deadlock
    ELSE
        -- is not a deadlock
END CATCH

Полный пример здесь в MSDN о том, как реализовать логику повтора взаимоблокировки исключительно в SQL.

146
ответ дан 24 November 2019 в 07:30
поделиться

Поскольку я предполагаю, что вы, возможно, захотите обнаруживать тупиковые ситуации, чтобы иметь возможность повторить неудачную операцию, я хотел бы предупредить вас за небольшую ошибку. Надеюсь, вы извините меня за то, что я немного отклонился от темы.

Обнаруженный базой данных тупик приведет к откату транзакции, в которой вы работали (если таковая была), в то время как соединение остается открытым в .NET. Повторная попытка выполнения операции (в том же соединении) означает, что она будет выполнена в безтранзакционном контексте, что может привести к повреждению данных.

Важно помнить об этом. Лучше всего в случае сбоя, вызванного SQL, считать все соединение обреченным. Повторная попытка выполнения операции может быть сделана только на уровне, где определена транзакция (путем воссоздания этой транзакции и ее соединения).

Поэтому, когда вы повторяете неудачную операцию, пожалуйста, убедитесь, что вы открыли совершенно новое соединение и начали новую транзакцию.

43
ответ дан 24 November 2019 в 07:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: