14

查看 SQL Server 联机丛书,Microsoft 似乎有一种(不正确的)方法来处理存储过程中的嵌套事务

嵌套事务

显式事务可以嵌套。这主要是为了支持存储过程中的事务,这些事务既可以从已经在事务中的进程调用,也可以从没有活动事务的进程调用。

该示例继续显示启动自己的事务的存储过程(“无论执行它的任何进程的事务模式如何,该过程都会强制执行其事务。”)

CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS
   BEGIN TRANSACTION InProc
      ...
   COMMIT TRANSACTION InProc;

然后可以在不运行事务的情况下调用此过程:

EXECUTE TransProc 3,'bbb';

使用显式事务:

BEGIN TRANSACTION OutOfProc;

EXEC TransProc 1, 'aaa';

COMMIT TRANSACTION OutOfProc

他们没有解决的是当存储产品时会发生什么:

  • 失败并出现错误,但让事务继续运行
  • 失败并出现错误,但不会让事务继续运行
  • 遇到错误,但在事务打开的情况下继续执行
  • 遇到错误,但在事务回滚的情况下继续执行

没有:

  • SET XACT_ABORT ON
  • @@TRANCOUNT

规范示例中的任何位置。

如果我不知道更好,我会认为这条线:

以下示例显示了嵌套事务的预期用途。

实际上应该阅读

以下示例显示了如何不使用嵌套事务。

除非有人能对这个 BOL 示例做出正面或反面?

4

2 回答 2

44

您需要对事务使用 try catch 块。因此,如果您在 catch 块中遇到错误,那么您可以回滚您的事务。

请参阅下面的 sql server 代码。

BEGIN TRANSACTION;

BEGIN TRY
    -- Some code
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH

    ROLLBACK TRANSACTION;
END CATCH;
于 2012-11-01T05:28:49.870 回答
16
CREATE PROCEDURE [usp_my_procedure_name]
AS
BEGIN
  SET NOCOUNT ON;
  DECLARE @trancount int;
  SET @trancount = @@trancount;
  BEGIN TRY
    IF @trancount = 0
      BEGIN TRANSACTION
      ELSE
        SAVE TRANSACTION usp_my_procedure_name;

    -- Do the actual work here

    lbexit:
      IF @trancount = 0
      COMMIT;
  END TRY
  BEGIN CATCH
    DECLARE @error int,
            @message varchar(4000),
            @xstate int;

    SELECT
      @error = ERROR_NUMBER(),
      @message = ERROR_MESSAGE(),
      @xstate = XACT_STATE();

    IF @xstate = -1
      ROLLBACK;
    IF @xstate = 1 AND @trancount = 0
      ROLLBACK
    IF @xstate = 1 AND @trancount > 0
      ROLLBACK TRANSACTION usp_my_procedure_name;

    RAISERROR ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message);
  END CATCH
END
于 2013-02-06T12:50:08.637 回答