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