TransactionScope, преждевременно завершенный

У меня есть блок кода, который работает в TransactionScope и в рамках этого блока кода, я выполняю несколько вызовов к DB. Выбирает, Обновления, Создает и Удаляет, целая палитра. Когда я выполняю мой удалять, я выполняю его с помощью дополнительного метода SqlCommand, который автоматически повторно отправит запрос, если это зайдет в тупик, поскольку этот запрос мог бы потенциально поразить мертвую блокировку.

Я полагаю, что проблема происходит, когда мертвая блокировка поражена, и функция пытается повторно отправить запрос. Это - ошибка, которую я получаю:

Транзакция, связанная с текущим соединением, завершилась, но не была расположена. Транзакция должна быть расположена, прежде чем соединение может использоваться для выполнения SQL-операторов.

Это - простой код, который выполняет запрос (весь код ниже выполняется в рамках использования TransactionScope):

using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
    sqlCommand.Connection.Open();
    sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}

Вот дополнительный метод, который повторно отправляет заведенный в тупик запрос:

public static class SqlCommandExtender
{
    private const int DEADLOCK_ERROR = 1205;
    private const int MAXIMUM_DEADLOCK_RETRIES = 5;
    private const int SLEEP_INCREMENT = 100;

    public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand)
    {
        int count = 0;
        SqlException deadlockException = null;

        do
        {
            if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT);
            deadlockException = ExecuteNonQuery(sqlCommand);
            count++;
        }
        while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES);

        if (deadlockException != null) throw deadlockException;
    }

    private static SqlException ExecuteNonQuery(SqlCommand sqlCommand)
    {
        try
        {
            sqlCommand.ExecuteNonQuery();
        }
        catch (SqlException exception)
        {
            if (exception.Number == DEADLOCK_ERROR) return exception;
            throw;
        }

        return null;
    }
}

Ошибка происходит на строке:

sqlCommand.ExecuteNonQuery();
64
задан abatishchev 25 April 2013 в 18:15
поделиться

2 ответа

Не забывайте подавлять операторы select в TransactionScope. В SQL Server 2005 и выше, даже когда вы используете with(nolock), блокировки все равно создаются на тех таблицах, которые затрагивает select. Посмотрите здесь, здесь показано как настроить и использовать TransactionScope.

using(TransactionScope ts = new TransactionScope 
{ 
  // db calls here are in the transaction 
  using(TransactionScope tsSuppressed = new TransactionScope (TransactionScopeOption.Suppress)) 
  { 
    // all db calls here are now not in the transaction 
  } 
} 
60
ответ дан 24 November 2019 в 15:46
поделиться

Если исключение происходит внутри TransactionScope , выполняется откат. Это означает, что TransactionScope завершен. Теперь вы должны вызвать для него dispose () и начать новую транзакцию. Честно говоря, я не уверен, можно ли повторно использовать старую TransactionScope или нет, я никогда не пробовал, но полагаю, что нет.

11
ответ дан 24 November 2019 в 15:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: