【问题标题】:SqlException: DeadlockSqlException:死锁
【发布时间】:2010-11-30 10:18:46
【问题描述】:

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

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

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

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];
 }

这些每次都会发生。

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

【问题讨论】:

标签: c# sql deadlock database-deadlocks


【解决方案1】:

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

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

无论如何,借助死锁图和其他查询,您应该能够判断哪些资源正在死锁。经典的解决方案是更改两个查询的顺序,以便以相同的顺序访问资源——这避免了循环。

你可以做的其他事情:

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

【讨论】:

    【解决方案2】:

    并不是说这会解决死锁问题,但您应该像处理 SqlConnection 一样处理其他 IDisposable 对象:

        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'
    

    我想明确一点,您允许使用此解决方案读取未提交的数据。这是交易系统中的风险。 Read this answer。希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      基本上,SQL Server 并发模型使您永远无法避免此异常(例如,完全不相关的事务可能会相互阻塞,如果它们碰巧锁定了相同的索引页面或其他东西)。您可以做的最好的事情是让您的交易保持简短以减少可能性,如果您遇到异常,请按照它所说的去做并重试交易。

      【讨论】:

      • 您混淆了阻塞和死锁的概念。这个例外是不可避免的,这根本不是真的。
      • 不,我不是。如果您使用默认锁定(有时是行锁,有时是页锁),很容易看出两个不相关的事务可能会意外地相互死锁(至少如果它们更新事务内的两个表并且您不使用提示来确保表总是以相同的顺序读取)。对于 rowlock 情况,它不太明显,但索引可以在这里咬你。
      猜你喜欢
      • 2015-11-23
      • 1970-01-01
      • 2011-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-27
      • 2014-06-08
      • 2013-11-30
      相关资源
      最近更新 更多