EXECUTE 后的事务计数表明 BEGIN 和 COMMIT 的数量不匹配

P. *_*een 5 sql-server transactions entity-framework-6

当以下过程中发生任何错误时,错误消息为“EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数量不匹配。上一页count = 1, current count = 0。EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数量不匹配。上一页count = 1, current count = 0

CREATE PROCEDURE [dbo].[proc_PurchaseOrder_Create](@CustomerID INT, @CustomerOrderID INT OUTPUT)          
AS          
SET NOCOUNT ON;          
--------------------------------          
DECLARE @Return_Message VARCHAR(1024)          
DECLARE @ErrorCode  INT            
DECLARE @ErrorStep  VARCHAR(200)          
DECLARE @UserID INT  
--------------------------------          
DECLARE @CustomerCartID INT,@PONumber VARCHAR(255), @CartTotalAmount NUMERIC          

BEGIN TRY          

    BEGIN TRAN                  
  -----------------------------------------------------------------------------             
  SELECT @ErrorCode = @@ERROR          
      SET NOCOUNT ON;      
  IF NOT EXISTS(SELECT CustomerCartID FROM TxnCustomerCart WHERE CustomerID = @CustomerID)           
     BEGIN          
        SET @Return_Message= 'No Cart item is available'          
           SET @ErrorCode = 1          
        END                  
        ELSE          
        BEGIN          
    -----------------------------------------------------------------------------          
    SELECT @UserID = ISNULL(UserID,0) FROM TxnCustomers WHERE CustomerID = @CustomerID      
    -----------------------------------------------------------------------------          
    SELECT @CartTotalAmount = CartTotalAmount, @CustomerCartID = CustomerCartID FROM TxnCustomerCart WHERE @CustomerID = CustomerID            
    SELECT @ErrorStep = 'Error on inserting data into TxnCustomerOrders';            
    INSERT INTO TxnCustomerOrders(CustomerID,OrderDate,OrderStatus,Ramarks,PaymentCategoryCode,CreatedBy,CreatedDatetime)          
    VALUES(@CustomerID,GETDATE(),'PRTRCVD','','Wallet',@UserID,GETDATE())            
    SET @CustomerOrderID = SCOPE_IDENTITY();          

    SELECT @ErrorStep = 'Error on generating PONumber';            
    SET @PONumber =dbo.fun_getPONumber(@CustomerID, @CustomerOrderID)          

    SELECT @ErrorStep = 'Error on inserting data into TxnPurchaseOrder';          

    INSERT INTO TxnPurchaseOrder (CustomerOrderID, PONumber, PODate, POAmount, PODocID, PODocPath, CreatedBy, CreatedDate)          
     VALUES (@CustomerOrderID, @PONumber, GETDATE(), @CartTotalAmount, REPLACE(@PONumber, '/' , '-'), REPLACE(@PONumber, '/' , '-') + '.pdf', @UserID, GETDATE())              

    SELECT  @ErrorCode  = 0, @Return_Message = 'Purchase order successfully created'          
  END       

  SET NOCOUNT OFF;         
    COMMIT TRAN               
    RETURN @ErrorCode -- =0 if success,  <>0 if failure          
END TRY           
BEGIN CATCH          
    IF @@TRANCOUNT > 0 ROLLBACK          

    SELECT @ErrorCode = ERROR_NUMBER()          
        , @Return_Message = @ErrorStep + ' '          
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '          
     + cast(ERROR_LINE() as varchar(20)) + ' '           
        + ERROR_MESSAGE() + ' > '           
        + ERROR_PROCEDURE()          

    RETURN @ErrorCode -- =0 if success,  <>0 if failure          

END CATCH  
Run Code Online (Sandbox Code Playgroud)

And*_*zov 3

您还需要考虑 XACT_STATE() 函数的结果。检查MSDN上的不可提交事务和 XACT_STATE

\n\n
\n\n

稍后编辑

\n\n
\n\n

我改变了对可能的解决方案的想法:)\n最后我重现了您的情况。看。\n我采用了您的过程,删除了除与异常处理和逻辑相关的代码之外的所有代码try\\catch,并添加了将导致对象名称解析错误(致命错误)的表达式。这是我得到的

\n\n
CREATE PROCEDURE [dbo].[proc_PurchaseOrder_Create]         \nAS          \nSET NOCOUNT ON;          \nBEGIN TRY          \n\n    BEGIN TRAN   \n\n    print \'before\'\n    select * from ##global_tmp_table; --> fatal error here\n    print \'after\'\n\n    COMMIT TRAN         \nEND TRY           \nBEGIN CATCH\n    print \'catch\'\n    IF @@TRANCOUNT > 0 ROLLBACK          \nEND CATCH  \n
Run Code Online (Sandbox Code Playgroud)\n\n

好的,现在如果我尝试执行此过程,我会得到以下输出

\n\n

之前\n消息 208,级别 16,状态 0,过程 proc_PurchaseOrder_Create,第 29 行\n无效的对象名称 \'##global_tmp_table\'。\n消息 266,级别 16,状态 2,过程 proc_PurchaseOrder_Create,第 29 行\nEXECUTE 后的事务计数表示BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 0,当前计数 = 1。

\n\n

所以发生了什么事?-我们的交易保持开放状态- 您可以通过print @@TRANCOUNT在同一窗口中执行来检查这一点

\n\n

为什么会发生这种情况?-因为 catch 块无法捕获致命错误- 来自我之前提到的同一篇 MSDN文章

\n\n

当以下类型的错误发生在与 TRY\xe2\x80\xa6CATCH 构造相同的执行级别时,CATCH 块不会处理这些错误:\n阻止批处理运行的编译错误,例如语法错误。\n错误在语句级重新编译期间发生的错误,例如由于延迟名称解析而在编译后发生的对象名称解析错误。

\n\n

在我们修复这种情况之前,您需要ROLLBACK在尝试执行存储过程的窗口中进行调用,以便最终关闭我们的事务。

\n\n

我们该如何解决这个问题?- 我们只需要- 您可以在使用 TRY\xe2\x80\xa6CATCH 和 XACT_STATE块的set XACT_ABORT ON所有同一篇文章中找到示例

\n\n

所以,最后,我们的测试程序应该是这样的

\n\n
ALTER PROCEDURE [dbo].[proc_PurchaseOrder_Create]         \nAS          \nSET NOCOUNT ON;  \nSET XACT_ABORT ON; --> the only change\nBEGIN TRY          \n\n    BEGIN TRAN   \n\n    print \'before\'\n    select * from ##global_tmp_table;\n    print \'after\'\n\n    COMMIT TRAN         \nEND TRY           \nBEGIN CATCH\n    print \'catch\'\n    IF @@TRANCOUNT > 0 ROLLBACK          \nEND CATCH \n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,在出现致命错误的情况下,数据库引擎将自动回滚事务,您将只得到预期的错误消息

\n\n

之前\n消息 208,级别 16,状态 0,过程 proc_PurchaseOrder_Create,第 31 行\n无效的对象名称 \'##global_tmp_table\'。

\n