您是否只在启动交易时才需要调用SET XACT_ABORT?

时间:2011-04-18 18:56:32

标签: sql-server

我想澄清一下这个答案 - > Nested stored procedures containing TRY CATCH ROLLBACK pattern?

以下是上述链接中的代码示例

 1 CREATE PROCEDURE [Name]
 2 AS
 3 SET XACT_ABORT, NOCOUNT ON
 4
 5 DECLARE @starttrancount int
 6
 7 BEGIN TRY
 8    SELECT @starttrancount = @@TRANCOUNT
 9
10    IF @starttrancount = 0
11        BEGIN TRANSACTION
12
13       [...Perform work, call nested procedures...]
14
15    IF @starttrancount = 0 
16        COMMIT TRANSACTION
17 END TRY
19 BEGIN CATCH
20    IF XACT_STATE() <> 0 AND @starttrancount = 0 
21        ROLLBACK TRANSACTION
22    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
23 END CATCH
24 GO

假设从启动事务的旧存储过程调用它。 在这种情况下,此proc不会启动它自己的事务,但会改变调用的XACT_ABORT状态。

所以,我在这里有几个问题。

  • 当前XACT_ABORT是否有效 仅处理,或整个电话 堆栈?
  • 如果我想重构一个proc来使用 SET XACT_ABORT ON,我需要配对吗? 它与SET XACT_ABORT关闭?这是遗留代码最安全的方法吗?

下面是修改后的样本,它会有条件地打开XACT_ABORT并将其配对,并在proc出口处将其关闭

CREATE PROCEDURE [Name]
AS
SET NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
   SELECT @starttrancount = @@TRANCOUNT

   IF @starttrancount = 0
   BEGIN
      SET XACT_ABORT ON
      BEGIN TRANSACTION
   END

      [...Perform work, call nested procedures...]

   IF @starttrancount = 0 
   BEGIN
      COMMIT TRANSACTION
      SET XACT_ABORT OFF
   END
END TRY
BEGIN CATCH
   IF XACT_STATE() <> 0 AND @starttrancount = 0 
   BEGIN
       ROLLBACK TRANSACTION
       SET XACT_ABORT OFF
   END
   RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

3 个答案:

答案 0 :(得分:4)

据我所知,当子批次的执行结束时,它会恢复此设置的先前值。

SET NOCOUNT ON;

BEGIN TRAN

SELECT CASE
         WHEN 16384 & @@OPTIONS = 16384
           THEN 'XACT_ABORT IS ON'
         ELSE ' XACT_ABORT IS OFF'
       END

CREATE TABLE #T
  (
     C INT
  )

SET XACT_ABORT OFF

INSERT INTO #T
VALUES      (1)

EXEC ('SET XACT_ABORT ON; 
      INSERT INTO #T VALUES(2);
        SELECT CASE
                    WHEN 16384 & @@OPTIONS = 16384
                    THEN ''XACT_ABORT IS ON''
                    ELSE '' XACT_ABORT IS OFF''
                END 
      ')


INSERT INTO #T
VALUES      (1 / 0)

/*If XACT_ABORT was on we would never get here but we do!*/
COMMIT

SELECT *
FROM   #T

DROP TABLE #T

SELECT CASE
         WHEN 16384 & @@OPTIONS = 16384
           THEN 'XACT_ABORT IS ON'
         ELSE ' XACT_ABORT IS OFF'
       END 

返回

------------------
 XACT_ABORT IS OFF


------------------
XACT_ABORT IS ON

Msg 8134, Level 16, State 1, Line 31
Divide by zero error encountered.
The statement has been terminated.
C
-----------
1
2


------------------
 XACT_ABORT IS OFF

答案 1 :(得分:0)

XACT_ABORT仅对当前proc或整个调用堆栈有效吗?    - 当设置为ON时,从该点开始对所有连接都是活动的

如果我想重构一个proc以使用SET XACT_ABORT ON,我是否需要将它与SET XACT_ABORT OFF配对?
- 如果这是你想要的行为,是的 - 这意味着你没有从遗留代码中获得新的行为。

对遗留代码来说,这是最安全的方法吗? - 为了最小化对其他存储过程的影响,是

答案 2 :(得分:0)

在我看来,它仅适用于SET的存储过程,并在以下时间重置:

如果SET语句在存储过程或触发器中运行,则在存储过程或触发器返回控制之后,将恢复SET选项的值。另外,如果您在通过使用sp_executesql或EXECUTE运行的动态SQL字符串中指定SET语句,则在控制从动态SQL字符串中指定的批处理返回后,将恢复SET选项的值。

https://docs.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql?view=sql-server-ver15#considerations-when-you-use-the-set-statements

从该页面我还不清楚嵌套proc中的行为是什么。