SQL Server中的嵌套过程回滚?

时间:2018-03-30 06:37:25

标签: sql-server

以下是外部和嵌套过程的代码

ALTER PROCEDURE dbo.NestedProcedure
AS
BEGIN
    SET XACT_ABORT OFF
    SET NOCOUNT ON
    BEGIN TRY
        DECLARE @trancount INT
        SET @trancount = @@TRANCOUNT
        IF @trancount = 0
            BEGIN TRANSACTION
        ELSE 
            SAVE TRANSACTION NestedProcedure

            ALTER TABLE dbo.Table_2
            ALTER COLUMN Column3 VARCHAR
        IF @trancount = 0
            COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        SELECT XACT_STATE()
        DECLARE @error INT, @message VARCHAR(4000), @xstate INT;
        SELECT @error = ERROR_NUMBER(), @message = ERROR_MESSAGE();
        IF XACT_STATE() = -1
        BEGIN
            ROLLBACK
        END
        IF XACT_STATE() = 1 AND @trancount = 0
        BEGIN
            ROLLBACK
        END
        IF XACT_STATE() = 1 AND @trancount > 0
        BEGIN
            ROLLBACK TRANSACTION NestedProcedure
        END
        RAISERROR ('NestedProcedure: %d: %s', 16, 1, @error, @message)
    END CATCH
END

ALTER PROCEDURE dbo.OuterProcedure
AS
BEGIN
    SET XACT_ABORT OFF
    SET NOCOUNT ON
    BEGIN TRY
        DECLARE @trancount INT
        SET @trancount = @@TRANCOUNT
        IF @trancount = 0
            BEGIN TRANSACTION
        ELSE 
            SAVE TRANSACTION OuterProcedure
            EXEC dbo.NestedProcedure
            SELECT * FROM dbo.Table_2
        IF @trancount = 0
            COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        SELECT XACT_STATE()
        DECLARE @error INT, @message VARCHAR(4000), @xstate INT;
        SELECT @error = ERROR_NUMBER(), @message = ERROR_MESSAGE();
        IF XACT_STATE() = -1
        BEGIN
            ROLLBACK
        END
        IF XACT_STATE() = 1 AND @trancount = 0
        BEGIN
            ROLLBACK
        END
        IF XACT_STATE() = 1 AND @trancount > 0
        BEGIN
            ROLLBACK TRANSACTION OuterProcedure
        END
        RAISERROR ('OuterProcedure: %d: %s', 16, 1, @error, @message)
    END CATCH
END

我正在调用OuterProcedure

EXEC dbo.OuterProcedure

我收到类似

的错误
  

Msg 50000,Level 16,State 1,Procedure OuterProcedure,Line 34
  OuterProcedure:50000:NestedProcedure:4922:ALTER TABLE ALTER COLUMN Column3失败,因为一个或多个对象访问此列

对于嵌套过程,

XACT_STATE()为-1是正确的,因为错误是可以理解的,但为什么即使对于外部过程,XACT_STATE()也变为-1?我只打算将嵌套过程回滚到保存点,无论它是否是运行时错误。有没有办法做到这一点?

1 个答案:

答案 0 :(得分:2)

XACT_STATE()为-1表示该事务是不可容许的。一旦进入此注定状态,就不会再在事务中提交任何类型的写入。某些类错误会导致事务进入此状态。遗憾的是,很难清楚地描述导致这些错误的错误类型。看看这篇文章是为了深入探讨。

http://www.sommarskog.se/error_handling/Part2.html#classification

另请参阅TRY..CATCH和XACT_STATE文档中的说明。

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql#uncommittable-transactions-and-xactstate

https://docs.microsoft.com/en-us/sql/t-sql/functions/xact-state-transact-sql

如果你真的需要你的外部程序做一些工作,你可能需要考虑更高级别的解决方法,尽管内部程序会破坏事务。一种方法是使用标志重试外部过程,以避免在第一次尝试导致此类错误时重复trasaction-dooming错误。