16

C# で SQL データベースからデータを取得しようとすると、次の 2 つの例外が生成されます。

System.Data.SqlClient.SqlException: トランザクション (プロセス ID 97) が別のプロセスのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。

また

System.Data.SqlClient.SqlException: トランザクション (プロセス ID 62) が別のプロセスのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。

また

System.Data.SqlClient.SqlException: トランザクション (プロセス ID 54) が別のプロセスのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。

これはコードです:

 using (SqlConnection con = new SqlConnection(datasource))
 {
    SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con);
    cmd.CommandTimeout = 300;
    con.Open();
    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    con.Close();
    return ds.Tables[0];
 }

これらは毎回起こりました。

これらをどのように解決できるかについてのアイデアはありますか?

4

3 に答える 3

26

受け取るデッドロックの数を減らすためにできることと、デッドロックを完全になくすためにできることがいくつかあります。

まず、SQL Server プロファイラーを起動し、デッドロック グラフを表示するように指示します。このトレースを実行すると、競合している他のクエリがわかります。あなたのクエリは非常に単純ですが、SELECT *システム内の MyTable というテーブルからのクエリがあるとは思えません...

とにかく、デッドロック グラフとその他のクエリを使用すると、どのリソースがデッドロックしているかがわかります。古典的な解決策は、リソースが同じ順序でアクセスされるように両方のクエリの順序を変更することです。これにより、サイクルが回避されます。

他にできること:

  • クエリに正しいインデックスを適用するなどして、クエリを高速化します。
  • データベースでスナップショット分離を有効にSET TRANSACTION ISOLATION LEVEL SNAPSHOTし、必要に応じてトランザクションで使用します。また、row-versioning でコミットされた読み取りを有効にします。多くの場合、これはほとんどのデッドロックを完全に解消するのに十分です。トランザクション分離レベルについて読んでください。 あなたがしていることを理解してください。
于 2010-11-30T14:08:57.320 に答える
10

これがデッドロックの問題に役立つというわけではありませんが、他のIDisposableオブジェクトをそのまま処分するのと同じように処分する必要がありますSqlConnection

    using (SqlConnection con = new SqlConnection(datasource))
    using (SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con))
    {
        cmd.CommandTimeout = 300;
        con.Open();
        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
        using (DataSet ds = new DataSet())
        {
            adapter.Fill(ds);
            return ds.Tables[0];
        }
    }

したがって、クエリでロックヒントを使用してロックを回避できる場合があります。

Select * from MyTable with (nolock) Where ID='1'

ただし、明確にしたいのですが、このソリューションではコミットされていないデータの読み取りを許可しています。これは、トランザクション システムにおけるリスクです。この回答を読んでください。お役に立てれば。

于 2010-11-30T14:36:21.403 に答える
3

基本的に、SQL サーバーの同時実行モデルでは、この例外を回避することはできません (たとえば、まったく関係のないトランザクションが、同じインデックス ページなどをロックした場合、互いにブロックする可能性があります)。あなたができる最善のことは、可能性を減らすためにトランザクションを短くすることです.例外が発生した場合は、それが示すことを実行してトランザクションを再試行してください.

于 2010-11-30T13:58:09.897 に答える