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

当出现某些类型的错误时,您无法回滚到保存点。请参阅Martin Smith对Rollback transaction to savepoint on failed ALTER TABLE ... ADD CONSTRAINT的回答。您检测到这一点的方法是进行测试Xact_state()

但是,您的问题有些不同,因为您还尝试使用嵌套事务。嵌套事务在 SQL 中并不像我们期望的那样真正工作。

例如,这失败了Cannot roll back TR2. No transaction or savepoint of that name was found.

    开始交易 TR1;
    开始交易 TR2
    回滚交易 TR2
    提交事务 TR1

嵌套事务

  • SQL Server 数据库引擎忽略提交内部事务

  • ROLLBACK TRANSACTION 语句的 transaction_name 参数引用一组命名嵌套事务的内部事务是不合法的。transaction_name 只能引用最外层事务的事务名

Paul S. Randal 在每天的 SQL Server DBA 神话中进一步探讨了这一点:(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 
于 2012-12-27T16:17:21.833 回答