我的.NET应用程序的事件日志显示,从SQL Server读取时,它偶尔会死锁。这通常非常罕见,因为我们已经优化了查询以避免死锁,但有时仍然会发生死锁。在过去,我们在调用
ExecuteReader
在我们的
SqlCommand
实例。为了解决这个问题,我们添加了重试代码,只需再次运行查询,如下所示:
//try to run the query five times if a deadlock happends
int DeadLockRetry = 5;
while (DeadLockRetry > 0)
{
try
{
return dbCommand.ExecuteReader();
}
catch (SqlException err)
{
//throw an exception if the error is not a deadlock or the deadlock still exists after 5 tries
if (err.Number != 1205 || --DeadLockRetry == 0)
throw;
}
}
对于死锁发生在初始查询执行期间的情况,这非常有效,但是现在我们在使用
Read()
函数在返回的
SqlDataReader
。
同样,我不关心优化查询,只是在极少发生死锁的情况下尝试恢复。我在考虑使用类似的重试过程。我可以创建继承自
数据阅读器
它简单地覆盖了
Read
具有重试代码的函数。这样地:
public class MyDataReader : SqlDataReader
{
public override bool Read()
{
int DeadLockRetry = 5;
while (DeadLockRetry > 0)
{
try
{
return base.Read();
}
catch (SqlException ex)
{
if (ex.ErrorCode != 1205 || --DeadLockRetry == 0)
throw;
}
}
return false;
}
}
这是正确的方法吗?我想确保读者不会跳过记录。将重试
读
死锁后跳过任何行?另外,我应该打电话吗
Thread.Sleep
在两次重试之间给数据库时间以摆脱死锁状态,还是这就足够了。这个例子不容易复制,所以我想在修改任何代码之前先确认一下。
编辑:
如您所要求的,有关我的情况的更多信息:在一个案例中,我有一个执行查询的流程,它加载需要更新的记录ID列表。然后我使用
读
函数并对该记录运行更新过程,该过程最终将更新数据库中该记录的值。(不,无法在初始查询中执行更新,对于返回的每个记录,还会发生许多其他事情)。这个代码已经工作了一段时间了,但是我们为每个记录运行了相当多的代码,所以我可以想象其中一个进程正在为正在读取的初始表创建一个锁。
经过思考,Scottie使用数据结构来存储结果的建议可能会解决这种情况。我可以将返回的ID存储在
List<int>
然后循环。这样就可以立即移除行上的锁。
然而,我仍然有兴趣知道是否有一种通用的方法可以从读操作的死锁中恢复过来。