0
--Drop Table Tab1

Begin Transaction TR1; 
Save Transaction TR1;
    Create Table Tab1(f1 decimal(10,0));
    Begin Transaction TR2
    Save Transaction TR2
        insert into Tab1 values(1);
        Begin Transaction TR3;
        Save Transaction TR3;
            insert into Tab1 values(2);
            Begin Try 
                insert into Tab1 values('OK');
                Commit Transaction TR3;
            END TRY
            BEGIN Catch
                print 'catch'
                RollBack Transaction TR3;
            End Catch

        insert into Tab1 values(3);
        Commit Transaction TR2
    insert into Tab1 values(4);
Commit Transaction TR1;
--Commit Transaction;
select * from Tab1;
Drop Table Tab1

Select @@TRANCount

エラー発生:

メッセージ 3931、レベル 16、状態 1、行 17 現在のトランザクションをコミットできず、セーブポイントにロールバックできません。トランザクション全体をロールバックします。

これを処理する方法。

4

1 に答える 1

3

特定のタイプのエラーが発生すると、セーブ ポイントにロールバックできません。失敗した ALTER TABLE … ADD CONSTRAINT でトランザクションをセーブポイントにロールバックすることに対するMartin Smith の回答を参照してください。これを検出する方法は、テストすることです。Xact_state()

ただし、ネストされたトランザクションも使用しようとしているため、問題は多少異なります。ネストされたトランザクションは、期待どおりに SQL で実際には機能しません。

たとえば、これは失敗しますCannot roll back TR2. No transaction or savepoint of that name was found.

    トランザクション TR1 を開始します。
    取引開始 TR2
    ロールバック トランザクション TR2
    COMMIT トランザクション TR1

ネスティング トランザクションから

  • 内部トランザクションのコミットは、SQL Server データベース エンジンによって無視されます

  • ROLLBACK TRANSACTION ステートメントの transaction_name パラメータが、一連の名前付きネストされたトランザクションの内部トランザクションを参照することは正しくありません。transaction_name は、最も外側のトランザクションのトランザクション名のみを参照できます

Paul S. Randal は、A SQL Server DBA myth a day: (26/30) Nested transactions are realでこれをさらに詳しく説明しています。

あなたができる最善の方法は、代わりにセーブポイントを使用し、キャッチと最後に Xact_state を確認することです。

BEGIN TRANSACTION tr1; 

SAVE TRANSACTION tr2; 

CREATE TABLE tab1 
  ( 
     f1 DECIMAL(10, 0) 
  ); 

SAVE TRANSACTION tr3 

INSERT INTO tab1 
VALUES     (1); 

SAVE TRANSACTION tr4; 

INSERT INTO tab1 
VALUES     (2); 

BEGIN try 
    -- change the order of the follwoing two lines around to see the difference
    INSERT INTO tab1 VALUES (1 / 0); --Results in a rollback to savepoint
    INSERT INTO tab1 VALUES ('OK');  --Results in a complete rollback

    COMMIT TRANSACTION tr4; 
END try 

BEGIN catch 
    IF Xact_state() = -1 
      BEGIN 
          PRINT 'rollback transaction no other work can be done' 

          ROLLBACK TRANSACTION; 
      END 
    ELSE 
      BEGIN 
          PRINT 'rollback to savepoint' 

          ROLLBACK TRANSACTION tr4 
      END 
END catch 

IF Xact_state() > 0 
  BEGIN 
      INSERT INTO tab1 
      VALUES     (3); 

      INSERT INTO tab1 
      VALUES     (4); 

      COMMIT TRANSACTION tr1; 

      SELECT * 
      FROM   tab1; 

      DROP TABLE tab1 
  END 
于 2012-12-27T16:17:21.833 に答える