WCF服务导致SQL死锁错误

时间:2013-02-28 15:58:21

标签: sql wcf asynchronous dynamics-crm-2011 deadlock

在过去的几天里,我一直在用头撞墙,我似乎无法找到一个好的解决方案。

我有一个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;
}

1 个答案:

答案 0 :(得分:3)

您应该查看您使用的存储过程,以免产生死锁。 Sql旨在与多个请求并行工作。有一些方法可以检查代码并进行改进,以免陷入死锁。

如果不可能,您可以使用服务代理将请求排入sql server(如果使用支持它的sql server版本)。这意味着您必须稍后检查您的操作结果。

如果仍然不是这种情况(ms-sql&lt; 2005)那么你可以实现类似的东西。将您的请求写入表并使用作业来处理它。并再次检查操作结果。

如果您可以使用CLR存储过程,可以使用操作结果调用WCF服务,这样您就不需要定期检查数据库。

希望这有帮助。

作为编辑,您还可以检查SP中的死锁,并在出现错误时重试(检查错误号1205)