Как восстановить исключение взаимоблокировки во время SqlDataReader.Read ()

Журналы событий для моего .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 и просмотреть его. Таким образом, можно сразу снять блокировки строк.

Однако, Мне все еще было бы интересно узнать, есть ли общий способ выхода из тупиковых ситуаций при чтении.

5
задан InvisibleBacon 10 November 2010 в 16:40
поделиться