我们有客户端应用程序正在SQL Server 2005上运行一些SQL,如以下:

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应该对任何语言做出相同的响应。


当前回答

您可以在事务之前设置xact_abort,以确保sql在发生错误时自动回滚。

其他回答

您是正确的,整个事务将被回滚。您应该发出命令将其回滚。

您可以将其包装在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

    -- <EDIT>: From SQL2008 on, you must raise error messages as follows:
    DECLARE @ErrorMessage NVARCHAR(4000);  
    DECLARE @ErrorSeverity INT;  
    DECLARE @ErrorState INT;  

    SELECT   
       @ErrorMessage = ERROR_MESSAGE(),  
       @ErrorSeverity = ERROR_SEVERITY(),  
       @ErrorState = ERROR_STATE();  

    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
    -- </EDIT>
END CATCH

您可以在事务之前设置xact_abort,以确保sql在发生错误时自动回滚。

来自MDSN文章,控制事务(数据库引擎)。

If a run-time statement error (such as a constraint violation) occurs in a batch, the default behavior in the Database Engine is to roll back only the statement that generated the error. You can change this behavior using the SET XACT_ABORT statement. After SET XACT_ABORT ON is executed, any run-time statement error causes an automatic rollback of the current transaction. Compile errors, such as syntax errors, are not affected by SET XACT_ABORT. For more information, see SET XACT_ABORT (Transact-SQL).

在这种情况下,当任何插入失败时,它将回滚完整的事务。

如果其中一个插入失败,或者命令的任何部分失败,SQL server是否回滚事务?

不,不是。

如果它没有回滚,我是否必须发送第二个命令来回滚它?

当然,您应该发出ROLLBACK而不是COMMIT。

如果要决定是提交还是回滚事务,应该从语句中删除commit语句,检查插入的结果,然后根据检查结果发出commit或rollback。

下面是与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, @ErrorSeverity, @ErrorState);
END CATCH