1

私はここ数日、これで壁に頭を打ちつけてきましたが、良い解決策を思い付くことができないようです。

すべてのデータベースインタラクションの唯一のエントリポイントとして機能するWCFサービスがあります。現在のジレンマには、MicrosoftDynamicsCRM内の「AsyncOperation」テーブルに対してスピンするWindowsサービスがあります。CRMでエンティティレコードが作成されるたびに、WindowsサービスはAsyncOperationテーブルからレコードを取得し、そのデータを使用してWCFサービスに要求を送信します。私が直面している問題は、そのWindowsサービスがWCFサービスに対して同時に複数の要求を実行すると、サービスがSQLでトランザクションのデッドロックを引き起こすことです。

WCFサービス内のデータフローにログを追加しましたが、いつでも3〜5のリクエストが互いにミリ秒以内にサービスにヒットする可能性があることがわかりました。プロセスでは、サービスにヒットした最初のリクエストがデータベースに入る唯一のリクエストであり、残りはSQLデッドロックエラーを引き起こしているようです。

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

私の質問はこれです:SQL挿入がまったく同時に起こらないことを保証するWCFへのキューイングプロセスまたはシングルトンアプローチのいつかを実装する良い方法はありますか?私はMSDynamicsプラットフォーム上に構築しているため、複数の要求が同時に処理されないようにする方法がありません。システムに供給されるデータは外部パートナーから提供され、それらのいくつかは私たちのシステムにかなり大きな打撃を与えます。

私は解決策を見つけることを検討することができるどんな提案にもオープンです。

挿入を処理するWCFサービスのメソッドは次のとおりです。

public List<NoelGroup.Users.Core.Entity.BusinessLayer.PersonEntity> Insert(NoelGroup.Users.Core.Entity.BusinessLayer.PersonEntity businessObject)
{
    List<NoelGroup.Users.Core.Entity.BusinessLayer.PersonEntity> businessObjectList = null;

    using (SqlConnection conn = MainConnection)
    {
        int id = new Random().Next(9999);
        try
        {
            conn.Open();

            using (SqlCommand cmd = new SqlCommand("[crud].[usp_Person_InsertUpdate]", conn))
            {
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(new SqlParameter("@iui_PersonId", businessObject.PersonId));
                cmd.Parameters.Add(new SqlParameter("@ii_PrefixId", businessObject.PrefixId));
                cmd.Parameters.Add(new SqlParameter("@ivn_FirstName", businessObject.FirstName));
                cmd.Parameters.Add(new SqlParameter("@ivn_MiddleName", businessObject.MiddleName));
                cmd.Parameters.Add(new SqlParameter("@ivn_LastName", businessObject.LastName));
                cmd.Parameters.Add(new SqlParameter("@ic_Gender", businessObject.Gender));
                cmd.Parameters.Add(new SqlParameter("@ii_SuffixId", businessObject.SuffixId));
                cmd.Parameters.Add(new SqlParameter("@ii_PersonTypeId", businessObject.PersonTypeId));
                cmd.Parameters.Add(new SqlParameter("@id_BirthDate", businessObject.BirthDate));
                cmd.Parameters.Add(new SqlParameter("@iti_PreferredContactMethodId", businessObject.PreferredContactMethodId));
                cmd.Parameters.Add(new SqlParameter("@iv_ModifiedUsername", businessObject.ModifiedUsername));

                Logger.Log(string.Format("-- PersonEntity Insert ({1}) Execute -- {0}", DateTime.Now, id));
                using (SqlDataReader rdr = cmd.ExecuteReader())
                {
                    businessObject = null;
                    businessObject = new NoelGroup.Users.Core.Entity.BusinessLayer.PersonEntity();

                    businessObjectList = PopulateObjectsFromReader(rdr);
                }
                Logger.Log(string.Format("-- PersonEntity Insert ({1}) Complete -- {0}", DateTime.Now, id));
            }
        }
        catch(Exception ex)
        {
            throw new SeverityException(500, string.Format("PersonEntity::Insert ({0})::Error occured.", id), ex);
            //throw new SeverityException(500, "PersonEntity::Insert::Error occured.", ex);
        }
    }

    return businessObjectList;
}
4

1 に答える 1

3

デッドロックが発生しないように、使用するストアドプロシージャを確認する必要があります。SQLは、複数の要求と並行して機能することを目的としています。コードを確認して、デッドロックに陥らないように改善する方法があります。

これが不可能な場合は、サービスブローカーを使用してSQLサーバーへの要求をキューに入れることができます(それをサポートするバージョンのSQLサーバーを使用している場合)。つまり、後で操作の結果を確認する必要があります。

それでも当てはまらない場合(ms-sql <2005)は、同様の実装を行うことができます。テーブルにリクエストを書き込み、ジョブを使用して処理します。そして、操作の結果を後でもう一度確認してください。

CLRストアドプロシージャを使用できる場合は、操作の結果を使用してWCFサービスを呼び出すことができるため、DBを定期的にチェックする必要はありません。

お役に立てれば。

編集として、SPのデッドロックをチェックし、エラーが発生した場合に再試行することもできます(エラー番号1205をチェックしてください)

于 2013-02-28T16:04:52.810 に答える