私はここ数日、これで壁に頭を打ちつけてきましたが、良い解決策を思い付くことができないようです。
すべてのデータベースインタラクションの唯一のエントリポイントとして機能する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;
}