97

.NET 3.5 / C#アプリから、SQLServer2008インスタンスのデッドロックが原因である場合にのみSqlExceptionキャッチしたいと思います。

典型的なエラーメッセージはTransaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

それでも、この例外について文書化されたエラーコードではないようです。

メッセージ内のデッドロックキーワードの存在に対して例外をフィルタリングすることは、この動作を実現するための非常に醜い方法のようです。誰かがこれを行う正しい方法を知っていますか?

4

3 に答える 3

163

デッドロックのMicrosftSQLServer固有のエラーコードは1205であるため、SqlExceptionを処理して確認する必要があります。したがって、たとえば、他のすべてのタイプのSqlExceptionについて、バブルで例外を発生させたい場合は、次のようにします。

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

または、C#6で利用可能な例外フィルタリングを使用する

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

特定のメッセージの実際のSQLエラーコードを見つけるために行うと便利なことは、SQLServerのsys.messagesを調べることです。

例えば

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

純粋にSQL内でデッドロック再試行ロジックを実装する方法の完全な例がMSDNにあります。

于 2010-02-13T08:31:17.447 に答える
48

デッドロックを検出したいと思うかもしれないので、失敗した操作を再試行できるようにするために、ちょっとした落とし穴について警告したいと思います。ここで少し話題から外れてしまったことをお詫び申し上げます。

データベースによって検出されたデッドロックは、接続が.NETで開いたままになっている間、実行していたトランザクション(存在する場合)を効果的にロールバックします。その操作を(同じ接続で)再試行すると、トランザクションのないコンテキストで実行され、データが破損する可能性があります。

これを認識することが重要です。SQLが原因で障害が発生した場合は、完全な接続が運命づけられていると考えるのが最善です。操作の再試行は、トランザクションが定義されているレベルでのみ実行できます(そのトランザクションとその接続を再作成することによって)。

したがって、失敗した操作を再試行するときは、完全に新しい接続を開いて、新しいトランザクションを開始するようにしてください。

于 2010-02-13T13:26:11.630 に答える
5

デッドロックを検出するC#6の方法は次のとおりです。

try
{
    //todo: Execute SQL. 
    //IMPORTANT, if you used Connection.BeginTransaction(), this try..catch must surround that code. You must rollback the original transaction, then recreate it and re-run all the code.
}
catch (SqlException ex) when (ex.Number == 1205)
{
    //todo: Retry SQL
}

このtry..catchがトランザクション全体を囲んでいることを確認してください。@Steven(詳細については彼の回答を参照)によると、デッドロックが原因でsqlコマンドが失敗すると、トランザクションがロールバックされ、トランザクションを再作成しない場合、再試行は次のコンテキスト外で実行されます。トランザクションであり、データの不整合が発生する可能性があります。

于 2017-03-21T22:14:14.530 に答える