Обнаружение отката в SQL Server - PullRequest
0 голосов
/ 12 октября 2019

Попытка обнаружить условие отката, когда задействованы два или более операторов. Для SqlCommand.ExecuteNonQuery метода, документы говорят

Если не обнаружено ни одного оператора, способствующего подсчету, возвращаемое значение равно -1. Если происходит откат, возвращаемое значение также равно -1.

Я специально вставляю -1 как недопустимую запись в ссылочную таблицу, имеющую ограничения ссылочной целостности.

string sql = $@"
    BEGIN TRANSACTION
        BEGIN TRY
            DELETE FROM CustomerContact WHERE CustomerId = @Id
            INSERT INTO CustomerContact(CustomerId, ContactId) VALUES (3, -1)
            COMMIT TRANSACTION
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION
        END CATCH";

using (SqlCommand command = new SqlCommand(sql, connection))
{
    command.Connection.Open();
    command.Parameters.Add("Id", SqlDbType.Int).Value = id;
    int result = command.ExecuteNonQuery();
    Console.WriteLine(result); // -> returns affected deleted rows but not -1
}

Откат работает должным образом, но я не получаю -1 от ExecuteNonQuery, вместо этого я получаю количество затронутых строк из операции DELETE ( первыйоператор )

Я использовал SqlTransaction ранее, но я тестирую поведение транзакций на основе встроенного SQL.

1 Ответ

1 голос
/ 12 октября 2019

Я предлагаю вам просто вставить блок CATCH, чтобы указать на ошибку и произошел соответствующий откат, а не пытаться обнаружить сам ROLLBACK.

Рекомендуется указывать SET XACT_ABORT ON; для транзакций T-SQL, чтобы обеспечить немедленный откат транзакции в случае тайм-аута. Это связано с тем, что тайм-ауты происходят на стороне клиента, где API отменяет запущенный запрос и предотвращает выполнение блока CATCH с ROLLBACK. Затем соединение возвращается в пул с открытой транзакцией, и блокировки еще не сняты. Хотя транзакция будет в конечном итоге откатываться при повторном использовании / сбросе или закрытии пулированного соединения, настройка XACT_ABORT приведет к тому, что это произойдет немедленно, и снимет блокировки ресурсов.

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

string sql = $@"
        SET XACT_ABORT ON;
        BEGIN TRY
            BEGIN TRANSACTION;
            DELETE FROM CustomerContact WHERE CustomerId = @Id;
            INSERT INTO CustomerContact(CustomerId, ContactId) VALUES (3, -1);
            COMMIT TRANSACTION;
        END TRY
        BEGIN CATCH
            IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
            THROW;
        END CATCH";

try
{
    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Connection.Open();
        command.Parameters.Add("Id", SqlDbType.Int).Value = id;
        int result = command.ExecuteNonQuery();
        Console.WriteLine(result); // -> returns affected deleted rows but not -1
    }
}
catch
{
    Console.WriteLine('handle exception here');
}
...