SQL Server - 事务回滚错误?

jon*_*ers 181 sql sql-server transactions sql-server-2005

我们有一个客户端应用程序在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;
Run Code Online (Sandbox Code Playgroud)

它由一个长字符串命令发送.

如果其中一个插入失败,或者命令的任何部分失败,SQL Server是否会回滚事务?如果它没有回滚,我是否必须发送第二个命令才能回滚?

我可以给出关于我正在使用的api和语言的细节,但我认为SQL Server应该对任何语言做出相同的响应.

小智 190

您可以set xact_abort on在事务之前放置以确保sql在发生错误时自动回滚.

  • 我需要关闭它还是每次会话? (7认同)
  • @Marc"xact_abort"的范围是在连接级别. (4认同)
  • @AlexMcMillan与INSERT不同,DROP PROCEDURE语句修改数据库结构,INSERT只与数据一起使用.所以它不能包含在事务中.我过于简单了,但基本上就是这样. (2认同)
  • @eksortso你错了。这对 Oracle 有效,它在 DDL 命令之前自动提交。SQL Server 支持 DDL 事务。 (2认同)

Raj*_*ore 184

你是正确的,因为整个交易将被回滚.您应该发出命令将其回滚.

您可以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
Run Code Online (Sandbox Code Playgroud)

  • 至少在SQL Server 2008R2及更高版本中,RAISERROR的语法不正确.有关正确的语法,请参见http://msdn.microsoft.com/en-us/library/ms178592.aspx. (23认同)
  • try catch使您能够捕获(并可能修复)错误并在需要时引发自定义错误消息. (12认同)
  • 我认为,"捕获和记录"比"捕获和修复"更频繁. (9认同)
  • 我更喜欢DyingCactus的解决方案,他的代码是1行要更改的。如果您的出于某些原因更好(或更可靠),请告诉我。 (2认同)
  • @BornToCode确保事务存在.假设您已经在给定条件下(在`try`中)回滚了您的事务,但代码在之后失败了.没有更多的交易,但你仍然会进入`catch`. (2认同)
  • 这个原始答案来自 2009 年。同时引发错误消息的方式已经过时了。我编辑了最新标准的答案。 (2认同)

sam*_*ise 35

这里获取错误消息与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
Run Code Online (Sandbox Code Playgroud)


小智 21

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

如果批处理中发生运行时语句错误(例如约束违规),则数据库引擎中的默认行为是仅回滚生成错误的语句.您可以使用SET XACT_ABORT语句更改此行为.执行SET XACT_ABORT ON后,任何运行时语句错误都会导致当前事务的自动回滚.SET XACT_ABORT不会影响编译错误,例如语法错误.有关更多信息,请参见SET XACT_ABORT(Transact-SQL).

在您的情况下,当任何插入失败时,它将回滚整个事务.

  • 我们需要处理语法错误?或编译错误?如果其中任何一个发生整个交易应该回滚 (3认同)

Qua*_*noi 10

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

不,不是的.

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

当然,你应该发出ROLLBACK而不是COMMIT.

如果要决定是提交还是回滚事务,则应从COMMIT语句中删除该句子,检查插入的结果,然后发出COMMIT或者ROLLBACK根据检查结果发出.

  • 当连接超时时,底层网络协议(例如"命名管道"或"TCP")会断开连接.当连接断开时,`SQL Server`将停止当前正在运行的所有命令并回滚事务. (2认同)