在过去的几天里,我一直在用头撞墙,我似乎无法找到一个好的解决方案。
我有一个WCF服务,它充当我们所有数据库交互的唯一入口点。在当前的困境中,有一个Windows服务在Microsoft Dynamics CRM中的“AsyncOperation”表中旋转。每当在CRM中创建实体记录时,Windows服务就会从AsyncOperation表中获取记录,并使用该数据向WCF服务发出请求。我遇到的问题是,当Windows服务同时向WCF服务发出多个请求时,该服务会导致SQL中的事务死锁。
我在WCF服务中的数据流中添加了一些额外的日志记录,我发现在任何给定的时间内,3-5个请求之间的任何时间都可以在几毫秒内完成。似乎在进程中第一个命中服务的请求是唯一一个进入数据库的请求,其余的最终导致sql死锁错误:
事务(进程ID 95)在锁定资源上死锁 另一个进程并被选为死锁受害者。重新运行 事务。
我的问题是:有没有一种很好的方法来实现WCF的排队过程或单例方法,以确保SQL插入不会在同一时间发生?由于我是在MS Dynamics平台之上构建的,因此我无法确保不会同时处理多个请求。输入系统的数据由外部合作伙伴提供,其中一些数据对我们的系统非常重要。
我愿意接受任何有关寻找解决方案的建议。
处理插入的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;
}
答案 0 :(得分:3)
您应该查看您使用的存储过程,以免产生死锁。 Sql旨在与多个请求并行工作。有一些方法可以检查代码并进行改进,以免陷入死锁。
如果不可能,您可以使用服务代理将请求排入sql server(如果使用支持它的sql server版本)。这意味着您必须稍后检查您的操作结果。
如果仍然不是这种情况(ms-sql&lt; 2005)那么你可以实现类似的东西。将您的请求写入表并使用作业来处理它。并再次检查操作结果。
如果您可以使用CLR存储过程,可以使用操作结果调用WCF服务,这样您就不需要定期检查数据库。
希望这有帮助。
作为编辑,您还可以检查SP中的死锁,并在出现错误时重试(检查错误号1205)