SqlException:死锁

时间:2010-11-30 10:18:46

标签: c# sql deadlock database-deadlocks

当我尝试从C#中的SQL数据库中获取数据时,我产生了这两个异常:

  

System.Data.SqlClient.SqlException:事务(进程ID 97)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。

OR

  

System.Data.SqlClient.SqlException:事务(进程ID 62)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。

OR

  

System.Data.SqlClient.SqlException:事务(进程ID 54)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。重新运行该交易。

这是代码:

 using (SqlConnection con = new SqlConnection(datasource))
 {
    SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con);
    cmd.CommandTimeout = 300;
    con.Open();
    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    con.Close();
    return ds.Tables[0];
 }

这些都是每次都发生的。

关于如何解决这些问题的任何想法?

3 个答案:

答案 0 :(得分:18)

您可以采取一些措施来减少您收到的死锁数量,并采取一些措施来彻底消除这些死锁。

首先,启动SQL Server Profiler并告诉它为您提供deadlock graph。运行此跟踪将告诉您其他查询与您的查询冲突。您的查询非常简单,但我严重怀疑您在系统中有一个名为MyTable的表SELECT *查询...

无论如何,使用死锁图和其他查询,您应该能够分辨出哪些资源是死锁的。经典的解决方案是更改两个查询的顺序,以便以相同的顺序访问资源 - 这可以避免循环。

你可以做的其他事情:

  • 通过应用正确的索引等方式加快查询速度。
  • 在数据库上启用快照隔离,并在适当的时候在事务中使用SET TRANSACTION ISOLATION LEVEL SNAPSHOT。同时启用read committed with row-versioning。在许多情况下,这足以完全消除大多数死锁。了解事务隔离级别。 Understand你正在做什么。

答案 1 :(得分:8)

这不会有助于解决死锁问题,但您应该处置其他IDisposable个对象,就像处置SqlConnection一样:

    using (SqlConnection con = new SqlConnection(datasource))
    using (SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con))
    {
        cmd.CommandTimeout = 300;
        con.Open();
        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
        using (DataSet ds = new DataSet())
        {
            adapter.Fill(ds);
            return ds.Tables[0];
        }
    }

您可以通过查询中的锁定提示来避免锁定:

Select * from MyTable with (nolock) Where ID='1'

希望这有帮助。

答案 2 :(得分:3)

基本上,SQL服务器并发模型使得您永远无法避免此异常(例如,如果碰巧锁定相同的索引页或其他内容,完全不相关的事务可能会阻塞彼此)。您可以做的最好的事情是保持您的交易简短以减少可能性,如果您得到例外,按照它说的做,并重试交易。