【问题标题】:TSQL try catch transaction error handling, transaction count mismatchTSQL try catch 事务错误处理,事务计数不匹配
【发布时间】:2011-11-29 18:31:40
【问题描述】:

我有一个存储过程,我通过以下方式从 C# 调用事务:

using (var dbContext = PowerToolsDatabase.GetDataContext())
{
    dbContext.Connection.Open();
    using (dbContext.Transaction = dbContext.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable))
    { 
        foreach (var element in package.AddOrUpdateElements)
        {
            dbContext.usp_Element_Commit( /* args */);
        }

        dbContext.Transaction.Commit();
    }
}

在那个存储过程中,有一个 try catch,并且在特定情况下执行的 try 部分内部有一个 RAISERROR

BEGIN TRY
    BEGIN TRANSACTION   
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    -- Perform Name Uniqueness check (for new)
    IF EXISTS ( SELECT PK.identifier --... )
    BEGIN

        RAISERROR(60000, 16, 1, 'dbo.usp_Element_Commit', 'Supplied Element Name (for new Element) already exists')

        RETURN

    END

    -- Do stuff         

    COMMIT TRANSACTION
END TRY
BEGIN CATCH

    IF XACT_STATE() <> 0
    BEGIN
        ROLLBACK TRANSACTION;
    END

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT
        @ErrorMessage = 'dbo.usp_Element_Commit -- ' + ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);

END CATCH;

当我运行它并在存储过程的 try 部分中点击 RAISERROR 时,我收到以下多个错误:

dbo.usp_Element_Commit -- Supplied Element Name (for new Element) already exists
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.

在不搞乱外部事务的情况下,处理错误和跳转到 catch 块的推荐方法是什么?

此外,如果我从存储过程中的 catch 块中删除回滚,那么我会得到相同的事务计数消息,其中先前计数 = 1,当前计数 = 2

【问题讨论】:

  • 出现错误时你的 C# 如何跳过 COMMIT?
  • @KM 从 dbContext.usp_Element_Commit 调用中抛出了一个 SqlException,因此它会跳转到封闭 using 块中的 dispose,该块在 c# 事务上调用 Rollback
  • @JNK 一次回滚会回滚所有内容。 WHILE XACT_STATE() 0 没有意义。你可以自己试试看。

标签: c# sql-server tsql ado.net transactions


【解决方案1】:

我将我的 sproc 更改为 follow this pattern 使用保存点或事务,具体取决于是否已经存在现有事务。它现在按预期工作。

BEGIN TRY
    declare @trancount int = @@trancount
    if @trancount = 0
        begin transaction
    else
        save transaction usp_element_commit_transaction;

    set transaction isolation level serializable

    -- Perform Name Uniqueness check (for new)
    IF EXISTS ( SELECT PK.identifier --... )
    BEGIN

        RAISERROR(60000, 16, 1, 'dbo.usp_Element_Commit', 'Supplied Element Name (for new Element) already exists')

        RETURN

    END

    -- Do stuff         

    COMMIT TRANSACTION
END TRY
BEGIN CATCH

    declare @xstate int = xact_state()
    if @xstate = -1
        rollback
    else if @xstate = 1 and @trancount = 0
        rollback
    else if @xstate = 1 and @trancount > 0
        rollback transaction usp_element_commit_transaction;

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT
        @ErrorMessage = 'dbo.usp_Element_Commit -- ' + ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);

END CATCH;

【讨论】:

    猜你喜欢
    • 2010-10-27
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多