Журналы событий для моего приложения .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
.
Опять же, я не беспокоюсь об оптимизации запроса, а просто пытаюсь восстановить в редком случае возникновения тупика,Я думал об использовании аналогичного процесса повтора.Я мог бы создать свой собственный класс, который наследуется от 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;
}
}
Это правильный подход?Я хочу быть уверен, что записи не пропускаются в читателе.Будет ли повторная попытка Read
после тупика пропустить какие-либо строки?Кроме того, следует ли мне вызывать Thread.Sleep
между повторными попытками, чтобы дать времени базе данных выйти из тупикового состояния, или этого достаточно.Этот случай нелегко воспроизвести, поэтому я хотел бы убедиться в этом перед тем, как изменить какой-либо код.
РЕДАКТИРОВАТЬ:
В соответствии с просьбой, еще немногоинформация о моей ситуации: в одном случае у меня есть процесс, который выполняет запрос, который загружает список идентификаторов записей, которые необходимо обновить.Затем я перебираю этот список идентификаторов, используя функцию Read
, и запускаю процесс обновления этой записи, который в конечном итоге обновит значение для этой записи в базе данных.(Нет, невозможно выполнить обновление в начальном запросе, для каждой возвращаемой записи происходит много других вещей).Некоторое время этот код работал нормально, но мы выполняем довольно много кода для каждой записи, поэтому я могу представить, что один из этих процессов создает блокировку для начальной таблицы, которую читают.
После некоторых размышлений предложение Скотти использовать структуру данных для хранения результатов, вероятно, исправит эту ситуацию.Я мог бы хранить идентификаторы, возвращенные в List<int>
и проходить через это.Таким образом, блокировки строк могут быть сразу удалены.
Однако мне все равно было бы интересно узнать, существует ли общий способ восстановления после тупиков при чтении.