TSQL попробуйте перехватить обработку ошибок транзакций, несоответствие количества транзакций - PullRequest
1 голос
/ 29 ноября 2011

У меня есть sproc, который я вызываю из 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();
    }
}

И в этом sproc есть try-catch и RAISERROR внутри try-части, которая выполняется под определеннымобстоятельства

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;

Когда я запускаю это и нажимаю на RAISERROR в секции try sproc, я получаю следующие многочисленные ошибки:

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.

Каков рекомендуемый способ обработки ошибок ии перейти к блоку перехвата, не испортив внешнюю транзакцию?

Кроме того, если я удалю откат из блока перехвата в sproc, то получу то же самое сообщение Transaction Count с Previous Count = 1, current count = 2

1 Ответ

2 голосов
/ 30 ноября 2011

Я изменил свой sproc на , следуя этой схеме использования либо точки сохранения, либо транзакции в зависимости от того, существует ли уже существующая транзакция.И теперь все работает, как и ожидалось.

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;
...