首页 > 解决方案 > 什么类型的错误导致 MS SQL Server 中的 XACT_STATE 为 1?

问题描述

基于 Microsoft 文档关于 TRY...CATCH 当 XACT_STATE 为 -1 时,事务不可提交(TRY...CATCH (Transact-SQL)):

不可提交事务和 XACT_STATE

如果 TRY 块中产生的错误导致当前事务的状态无效,则该事务被归类为不可提交事务。当错误发生在 TRY 块内时,通常在 TRY 块外结束事务的错误会导致事务进入不可提交状态。不可提交的事务只能执行读取操作或 ROLLBACK TRANSACTION。该事务不能执行任何会生成写操作或 COMMIT TRANSACTION 的 Transact-SQL 语句。如果事务已被归类为不可提交事务,则 XACT_STATE 函数返回值 -1。批处理完成后,数据库引擎会回滚任何活动的不可提交事务。如果在事务进入不可提交状态时没有发送错误消息,则当批处理完成时,将向客户端应用程序发送错误消息。这表示检测到并回滚了一个不可提交的事务。

如果我理解正确,每个停止 TRY 块连续性并进入 CATCH 块的错误都会导致 XACT_STATE 为-1(当 XACT_ABORT 为 ON 时),但在上述文档的示例 C 中检查它是否为 1:

. . . END TRY BEGIN CATCH -- 执行错误检索例程。
执行 usp_GetErrorInfo;

-- Test XACT_STATE:  
    -- If 1, the transaction is committable.  
    -- If -1, the transaction is uncommittable and should   
    --     be rolled back.  
    -- XACT_STATE = 0 means that there is no transaction and  
    --     a commit or rollback operation would generate an error.  

-- Test whether the transaction is uncommittable.  
IF (XACT_STATE()) = -1  
BEGIN  
    PRINT  
        N'The transaction is in an uncommittable state.' +  
        'Rolling back transaction.'  
    ROLLBACK TRANSACTION;  
END;  

-- Test whether the transaction is committable.  
IF (XACT_STATE()) = 1  
BEGIN  
    PRINT  
        N'The transaction is committable.' +  
        'Committing transaction.'  
    COMMIT TRANSACTION;     

END; END CATCH; GO

我的问题在这里:

是错误的例子吗?如果不是,什么样的错误会导致 CATCH 块中的 XACT_STATE 为 1(可提交)?

标签: sql-servererror-handlingtransactionstry-catch

解决方案


SQL Server 可以容忍事务中的一些错误,而不必将其标记为不可提交。例如 SELECT 1/0 会导致错误,但不会强制事务进入不可提交状态。(引自https://docs.microsoft.com/en-us/azure/sql-data-warehouse/sql-data-warehouse-develop-transactions。)

事实上,除非 XACT_ABORT 打开,几乎任何非致命错误都会产生 1 的 XACT_STATE(pk 违规、数据类型转换、约束违规等)。(这取自https://www.sqlservercentral.com/Forums/Topic1109613-1550-1.aspx)。


推荐阅读