У меня есть блок кода, который выполняется в TransactionScope, и в этом блоке кода я делаю несколько вызовов БД. Выбирает, обновляет, создает и удаляет всю гамму. Когда я выполняю свое удаление, я выполняю его, используя метод расширения 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();