【发布时间】:2015-06-24 15:25:05
【问题描述】:
我在 SqlServer 2008 上经常遇到死锁。目前,我的数据访问层中有以下代码来处理它。它基本上捕获了死锁并尝试使用新连接重新提交命令。没有交易。但这似乎不起作用 - 用户仍然会遇到异常,我的日志显示大多数异常都是死锁。谁能告诉我我做错了什么?谢谢。
private static SqlDataReader ExecDataReader(SqlCommand comm, CommandBehavior behavior)
{
try { return comm.ExecuteReader(behavior); }
catch(SqlException ex)
{
if(ex.Number == 1205 && comm != null)
{
// Deadlock. Can't resubmit with the same connection,
// have to recreate it.
SqlParameterCollection pars = comm.Parameters;
string str = comm.Connection.ConnectionString;
string sproc = comm.CommandText;
int t = comm.CommandTimeout;
try
{
comm.Cancel();
if(comm.Connection != null &&
comm.Connection.State != ConnectionState.Closed)
comm.Connection.Close();
}
catch { }
// Trying to execute it after a random number of seconds
// in order not to get a deadlock again by executing both
// deadlocked commands at the same time. The GetRamdom
// method works as expected, returns totally random number
// in expected range
Thread.Sleep(GetRandom());
SqlConnection conn2 = new SqlConnection(str);
conn2.Open();
SqlCommand comm2 = conn2.CreateCommand();
comm2.CommandText = sproc;
comm2.CommandType = CommandType.StoredProcedure;
comm2.CommandTimeout = t;
CopyParameters(pars, comm2);
return ExecDataReader(comm2, behavior);
}
else throw;
}
}
【问题讨论】:
-
您必须查看导致死锁的原因才能解决您的问题。通常是两个连接尝试做同样的事情,但顺序不同。例如,如果进程 A 和 B 都放置了排他锁,连接 1 执行 A 然后 B,但连接 2 执行 B 然后 A,您可能会遇到每个连接都在等待另一个连接释放其锁的情况。根据我的经验,一个常见的原因是批量删除,因为它们很容易导致锁升级。尽量减少交易量也会有所帮助。
-
偶尔的死锁是不可避免的,没关系。频繁和/或常规的死锁不是。它们通常是由您的 SQL 查询、数据设计和数据库配置的某种组合引起的。所以你需要向我们展示这些。您发布到带有 SQL 标记的问题的 C# 代码看起来不错。
-
另一种避免死锁的方法是,如果您知道哪些代码位经常相互死锁,则使用
sp_getapplock在这些代码段周围放置一个“进程”锁。这会强制执行“关键路径”,以便一次只有一个进程可以尝试锁定名义资源。
标签: sql-server tsql sql-server-2008-r2 deadlock database-deadlocks