Как управлять вложенной транзакцией с помощью try catch

--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 Текущая транзакция не может быть зафиксирована и не может быть откатлена до точки сохранения. Откатить всю транзакцию.

Как справиться с этим.

1 ответ

Когда возникают ошибки определенного типа, вы не можете выполнить откат до точки сохранения. См Martin Smith Ответ Martin Smith на откат транзакции до точки сохранения при сбое ALTER TABLE… ADD CONSTRAINT. То, как вы обнаруживаете это, чтобы проверить Xact_state(),

Однако ваша проблема несколько иная, потому что вы также пытаетесь использовать вложенные транзакции. Вложенные транзакции на самом деле не работают в SQL, как мы ожидаем.

Например, это не с Cannot roll back TR2. No transaction or savepoint of that name was found.

    НАЧАЛО СДЕЛКИ TR1; 
    НАЧАЛО СДЕЛКИ TR2
    ROLLBACK TRANSACTION TR2
    COMMIT Транзакция TR1

Из вложенных транзакций

  • Фиксация внутренних транзакций игнорируется ядром базы данных SQL Server

  • Недопустимо, чтобы параметр транзакция_имя оператора ROLLBACK TRANSACTION ссылался на внутренние транзакции набора именованных вложенных транзакций. название транзакции может ссылаться только на имя самой внешней транзакции

Пол С. Рэндал исследует это далее в мифе администратора баз данных SQL Server в день: (26/30) вложенные транзакции реальны

Лучшее, что вы можете сделать, это использовать вместо этого точки сохранения и проверить 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 
Другие вопросы по тегам