3

ここで少し厳しい状況が発生しました。システムで時折デッドロックが発生しています。また、私はデータベースの同時実行に関して強いバックグラウンドをまったく持っていません。

System.Data.SqlClient.SqlException: Transaction (Process ID 69) was deadlocked on
lock resources with another process and has been chosen as the deadlock victim.
Rerun the transaction.

データベースにアクセスするアプリケーションはいくつかあります。Entity Framework を使用してデータベースにアクセスするメインの MVC アプリと、それぞれが ADO​​.NET と生の SQL を使用して DB にクエリを実行し、BinaryTap ActiveRecord を介してデータを挿入するいくつかの単純なコンソール アプリです。

残念ながら、私はクライアント組織の FNG であるため、新しいアイデアを展開してテストすることはできません。また、SSMS Express を使用しているため、SQL プロファイラーにアクセスできません。しかし、問題をすぐに修正することはそれほど重要ではなく、問題の分析を文書化することがより重要です。

トランザクションを再実行する必要があるというエラー メッセージに真実はありますか? これが DaoBase です。HttpContext ごとに 1 つの ObjectContext を (Db プロパティを介して) 使用しています。私たちは常に Dao の更新 (クエリではない) を SafeAction に入れているので、それらはトランザクションにラップされます。トランザクションを適切に再実行しようとしていますか?

public abstract class DaoBase
{
    protected static CaseMateEntities Db
    {
        get
        {
            return ContextHelper<CaseMateEntities>.GetCurrentContext();
        }
    }


    protected static void SafeAction(Action<ObjectContext> action)
    {
        Exception exception = null;

        try {
            using (var scope = new TransactionScope()) {
                try {
                    if (Db.Connection.State != ConnectionState.Open)
                        Db.Connection.Open();

                    if (action != null)
                        action(Db);

                    Db.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                    scope.Complete();
                } catch (Exception ex) {
                    exception = ex;
                    if (exception is UpdateException)
                        // TODO: Is this a proper way to rerun a transaction?
                        scope.Complete();
                }
            }

            if (exception == null) {
                Db.AcceptAllChanges();
            } else {
                throw exception;
            }
        } finally {
            Db.Connection.Close();
        }
    }
}

他のアプリは、ADO.NET/Raw SQL を介してデータベースにクエリを実行します。それぞれの SELECT ステートメントにはWITH (NOLOCK)指定がありません。純粋なクエリをロックしたい状況はありますか? また、クエリが作成するロックの種類は、行とページのロックですか? Entity Framework によって生成されたクエリについてはどうですか?クエリをロックしないように EF に指示する必要がありますか?

ここまで読んでくださった皆様、ありがとうございました。私はこれが複雑な問題であることを知っており、やるべきことがたくさんあります..

4

1 に答える 1

13

デッドロック分析では、SQL プロファイラーにアクセスして、デッドロックが発生した時点でデータベース サーバーの状況を確認する必要があります。特に、DB で実行される SQL クエリの所有者でない場合、これは必要です。EF を使用する場合、所有者ではありません。EF がクエリを生成します。デッドロックは、データベースクエリとトランザクションで実行されるデータベース操作の順序で解決する必要があります = データベースで何が起こったのかを知る必要があります。

分離レベルを操作するには、アプリケーションとデータベースで実行されている他のアプリケーションの両方について十分な知識が必要です。分離レベルをコミットされていない読み取りに設定すると、トランザクションのコア ルールの 1 つである分離が破られます。コミットされていない読み取りモードで実行されているトランザクションは、他のトランザクションによってコミットされていないデータ (ダーティ データ) を読み取ることができます。そのトランザクションがロールバックする場合、コードは無効なデータで動作し、データベースを不整合な状態に移動できます (または、データベースの制約で失敗します)。NOLOCKSQL クエリのヒントはグローバルにコミットされていない読み取りを使用するのと同じですが、ヒントは単一のクエリで単一のテーブルのみを対象としています。

NOLOCKコミットせずに使用または読み取るのは悪いことですか? いいえ、しかしいつそれを行うべきかを完全に確認する必要があります = アプリケーション (およびデータベースを使用する他のアプリケーション) を理解し、コミットされていないデータを取得するために使用されるこれらのクエリが他のデータ変更やリスク決定に使用されないようにする必要があります。

のデフォルトの分離レベルTransactionScopeは serializable です。これは、トランザクションに対して最も制限的なレベルです (= デッドロックがより頻繁に発生します)。データベースのロックを減らすために、読み取りコミット分離レベルを使用して開始する必要があります (ただし、トランザクション中に同じデータがデータベースから複数回読み取られないようにする必要があります) が、おそらく問題は解決しません (頻度を減らすことができます)。 )。分離レベルの詳細。

于 2011-12-12T23:35:03.590 に答える