首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C#中使用ADO进行有效的Sql Server死锁处理?

如何在C#中使用ADO进行有效的Sql Server死锁处理?
EN

Stack Overflow用户
提问于 2008-11-26 13:03:43
回答 4查看 35.3K关注 0票数 23

我有一个‘数据库’类,它可以作为ADO.net的包装器。例如,当我需要执行一个过程时,我调用Database.ExecuteProcedure(procedureName,parametersAndItsValues)。

我们在SQL Server 2000中遇到了严重的死锁问题。我们团队的一部分正在处理sql代码和事务,以最大限度地减少这些事件,但我正在考虑让这个数据库类在死锁情况下保持健壮。

我们希望死锁受害者可能会在一段时间延迟后重试,但我不知道这是否可能。下面是我们使用的一个方法的代码:

代码语言:javascript
复制
public int ExecuteQuery(string query)
{
    int rows = 0;

    try
    {
        Command.Connection = Connection;
        Command.CommandType = CommandType.Text;

        if(DatabaseType != enumDatabaseType.ORACLE)
          Command.CommandText = query;
        else
          Command.CommandText ="BEGIN " +  query + " END;";



        if (DatabaseType != enumDatabaseType.SQLCOMPACT)
            Command.CommandTimeout = Connection.ConnectionTimeout;

        if (Connection.State == ConnectionState.Closed)
            Connection.Open();

        rows = Command.ExecuteNonQuery();
    }
    catch (Exception exp)
    {
        //Could I add here any code to handle it?
        throw new Exception(exp.Message);
    }
    finally
    {
        if (Command.Transaction == null)
        {
            Connection.Close();
            _connection.Dispose();
            _connection = null;
            Command.Dispose();
            Command = null;
        }
    }
    return rows;
}

我能在catch块中做这个处理吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2008-12-02 22:18:50

首先,我要回顾一下我的SQL2000代码,并弄清楚为什么会发生这种死锁。修复这个问题可能隐藏了一个更大的问题(例如。缺少索引或查询错误)。

其次,我会检查我的架构,以确认死锁语句确实需要如此频繁地调用( select count(*) from bob必须每秒调用100次吗?)。

但是,如果您确实需要一些死锁支持,并且您的SQL或体系结构中没有错误,请尝试以下内容。(注意:我不得不在支持每秒数千次查询的系统中使用这种技术,并且很少会遇到死锁)

代码语言:javascript
复制
int retryCount = 3;
bool success = false;  
while (retryCount > 0 && !success) 
{
  try
  {
     // your sql here
     success = true; 
  } 
  catch (SqlException exception)
  {
     if (exception.Number != 1205)
     {
       // a sql exception that is not a deadlock 
       throw; 
     }
     // Add delay here if you wish. 
     retryCount--; 
     if (retryCount == 0) throw;
  }
}
票数 40
EN

Stack Overflow用户

发布于 2011-07-14 19:13:50

基于@Sam的响应,我提出了一个通用的重试包装方法:

代码语言:javascript
复制
private static T Retry<T>(Func<T> func)
{
    int count = 3;
    TimeSpan delay = TimeSpan.FromSeconds(5);
    while (true)
    {
        try
        {
            return func();
        }
        catch(SqlException e)
        {
            --count;
            if (count <= 0) throw;

            if (e.Number == 1205)
                _log.Debug("Deadlock, retrying", e);
            else if (e.Number == -2)
                _log.Debug("Timeout, retrying", e);
            else
                throw;

            Thread.Sleep(delay);
        }
    }
}

private static void Retry(Action action)
{
    Retry(() => { action(); return true; });
}

// Example usage
protected static void Execute(string connectionString, string commandString)
{
    _log.DebugFormat("SQL Execute \"{0}\" on {1}", commandString, connectionString);

    Retry(() => {
        using (SqlConnection connection = new SqlConnection(connectionString))
        using (SqlCommand command = new SqlCommand(commandString, connection))
            command.ExecuteNonQuery();
    });
}

protected static T GetValue<T>(string connectionString, string commandString)
{
    _log.DebugFormat("SQL Scalar Query \"{0}\" on {1}", commandString, connectionString);

    return Retry(() => { 
        using (SqlConnection connection = new SqlConnection(connectionString))
        using (SqlCommand command = new SqlCommand(commandString, connection))
        {
            object value = command.ExecuteScalar();
            if (value is DBNull) return default(T);
            return (T) value;
        }
    });
}
票数 24
EN

Stack Overflow用户

发布于 2008-12-02 10:22:04

如果死锁可以在数据层解决,那肯定是可行的方法。锁定提示,重新设计模块的工作方式等等。然而,NoLock并不是万能的--有时,出于事务完整性的原因,它是不可能使用的,我曾经遇到过直接(尽管复杂)读取所有相关表的数据未锁定的情况,这些情况仍然会导致其他查询上的阻塞。

不管怎样,如果你因为某种原因不能在数据层解决这个问题,那么

代码语言:javascript
复制
bool OK = false;
Random Rnd = new Random();

while(!OK)
{
    try
    {
        rows = Command.ExecuteNonQuery();
        OK = true;
    }
    catch(Exception exDead)
    {
        if(exDead.Message.ToLower().Contains("deadlock"))
            System.Threading.Thread.Sleep(Rnd.Next(1000, 5000));
        else
            throw exDead;
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/320636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档