SQL Server - транзакции возвращаются к ошибке?

У нас есть клиентское приложение, которое запускает SQL на SQL Server 2005, например:

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

Он отправляется одной длинной строковой командой.

Если одна из вложений не работает или какая-либо часть команды выходит из строя, SQL Server откатывает транзакцию? Если он не откат, мне нужно отправить вторую команду для ее возврата?

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

Ответ 1

Вы можете поместить set xact_abort on перед транзакцией, чтобы убедиться, что sql откатывается автоматически в случае ошибки.

Ответ 2

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

Вы можете обернуть это в блок TRY CATCH следующим образом

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

Ответ 3

Здесь код с получением сообщения об ошибке, работающего с MSSQL Server 2016:

BEGIN TRY
    BEGIN TRANSACTION 
        -- Do your stuff that might fail here
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN

        DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
        DECLARE @ErrorSeverity INT = ERROR_SEVERITY()
        DECLARE @ErrorState INT = ERROR_STATE()

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, -- Message text.  
               @ErrorSeverity, -- Severity.  
               @ErrorState -- State.  
               );
END CATCH

Ответ 4

Из статьи MDSN, Управление транзакциями (движок базы данных).

Если в пакете возникает ошибка инструкции времени выполнения (например, нарушение ограничения), поведение по умолчанию в Database Engine сводится к откату только инструкции, которая породила ошибку. Вы можете изменить это поведение, используя инструкцию SET XACT_ABORT. После выполнения SET XACT_ABORT ON любая ошибка выполнения во время выполнения вызывает автоматический откат текущей транзакции. SET XACT_ABORT не влияет на ошибки компиляции, такие как синтаксические ошибки. Для получения дополнительной информации см. SET XACT_ABORT (Transact-SQL).

В вашем случае он откатится от полной транзакции, если какая-либо из вставок не работает.

Ответ 5

Если одна из вложений не работает или какая-либо часть команды выходит из строя, SQL-сервер откатывает транзакцию?

Нет, это не так.

Если он не откат, мне нужно отправить вторую команду для ее возврата?

Конечно, вы должны выдать ROLLBACK вместо COMMIT.

Если вы хотите решить, следует ли совершать или откатывать транзакцию, вы должны удалить предложение COMMIT из инструкции, проверить результаты вставки и затем выдать либо COMMIT, либо ROLLBACK в зависимости от результатов проверки.