2017-06-12 3 views
1

Ich habe ein proc, die eine andere proc Name b ruft:Warum kann ich Prozedur mit Transaktion nicht innerhalb einer anderen Prozedur mit Transaktion aufrufen?

Create PROC a 
AS 
    BEGIN 
     BEGIN TRY 
      BEGIN TRANSACTION; 

      IF (1 = 1) 
       BEGIN 
        DECLARE @ReturnMessage VARCHAR(50); 
        EXEC dbo.b @ReturnMessage = @ReturnMessage OUTPUT; -- varchar(50) 

        IF (@ReturnMessage = 'aaaa') 
        begin 
         PRINT 'anuj'; 
         end 
       END; 
      COMMIT TRANSACTION; 
     END TRY 
     BEGIN CATCH 
      ROLLBACK TRANSACTION; 
     THROW; 
     END CATCH; 
    END; 

Die b proc ist:

Create PROC b 
    (
     @ReturnMessage VARCHAR(50) OUTPUT 
    ) 
AS 
    BEGIN 
     BEGIN TRY 
      BEGIN TRANSACTION; 
      IF (1 = 1) 
       BEGIN 

        ROLLBACK TRANSACTION; 
        SET @ReturnMessage = 'aaaa'; 
       RETURN; 
       END; 
      COMMIT TRANSACTION; 
     END TRY 
     BEGIN CATCH 
      ROLLBACK TRANSACTION; 
      THROW; 
     END CATCH; 

    END; 

Wenn ich Exec ausführen dbo.a

ich die folgende Meldung:

Msg 3903, Level 16, State 1, Procedure a, Line 20 [Batch Start Line 0] 
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION. 
Msg 266, Level 16, State 2, Procedure b, Line 0 [Batch Start Line 0] 
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0. 

Kann jemand sagen, was ich falsch gemacht habe? Dies ist nur ein Beispiel, das ich implementieren möchte. Gibt es eine bessere Art und Weise solche Transaktionen

UPDATE zu behandeln: OK Ich habe die folgenden Änderungen an meinem proc b verwendete ich Transaktion Sicherungspunkt und TRANCOUNT und seine Arbeit jetzt:

ALTER PROC b 
    (
     @ReturnMessage VARCHAR(50) OUTPUT 
    ) 
AS 
    BEGIN 
     BEGIN TRY 
      DECLARE @trancount INT; 
      SET @trancount = @@TRANCOUNT; 
      IF @trancount = 0 
       BEGIN 
        BEGIN TRANSACTION; 
       END; 
      ELSE 
       BEGIN 
        SAVE TRANSACTION b; 

        IF (1 = 1) 
         BEGIN 

          ROLLBACK TRANSACTION b; 
          SET @ReturnMessage = 'aaaa'; 
          RETURN; 
         END; 

       END; 

      IF (@trancount = 0) 
       COMMIT TRANSACTION; 
     END TRY 
     BEGIN CATCH 
      IF @trancount = 0 
       BEGIN 
        ROLLBACK TRANSACTION; 
       END; 
      ELSE 
       IF @trancount > 0 
        BEGIN 
         ROLLBACK TRANSACTION b; 
        END; 
      THROW; 
     END CATCH; 

    END; 
+2

Sie wissen, dass 'rollback' alles zurück, was rollt, nicht nur die zuletzt gestartete Transaktion, nicht wahr? Siehe https://stackoverflow.com/q/2265629/11683 und https://stackoverflow.com/q/12456579/11683. – GSerg

+0

Sie * können *. Wenn Sie jedoch Commits mit Rollbacks verwechseln, werden Sie leicht mit unerreichten Rollbacks oder verwaisten Transaktionen enden. –

+0

Fügen Sie einige Print-Anweisungen hinzu, um dem Flow zu folgen. Verwenden Sie auch @@ TRANCOUNT vor dem Rollback/Commit – SAS

Antwort

0

Handle Transaktionen in dem Verfahren, das gestartet die Transaktion mit throw ... Benutze @@ TRANCOUNT.

alter PROC a 
AS 
    declare @ret int; 

    BEGIN 
    BEGIN TRY 
     BEGIN TRANSACTION; 

     IF (1 = 1) 
      BEGIN 
       DECLARE @ReturnMessage VARCHAR(50); 
       EXEC @ret = dbo.b @ReturnMessage = @ReturnMessage OUTPUT; -- varchar(50) 
       if @ret <> 0 
       begin 
        ;throw 50000, 'ErrorA', 1; 
       end 

       IF (@ReturnMessage = 'aaaa') 
       begin 
        PRINT 'anuj'; 
        end 
      END; 
     COMMIT TRANSACTION; 
    END TRY 
    BEGIN CATCH 
     if @@TRANCOUNT > 0 
      ROLLBACK TRANSACTION; 
     THROW; 
    END CATCH; 
END; 

alter PROC b 
(
    @ReturnMessage VARCHAR(50) OUTPUT 
) 
AS 
BEGIN 
    BEGIN TRY 
     BEGIN TRANSACTION; 
     IF (1 = 1) 
      BEGIN 
       SET @ReturnMessage = 'aaaa'; 
       throw 50000, 'ErrorB', 1; 
       RETURN 1; 
      END; 
     COMMIT TRANSACTION; 
    END TRY 
    BEGIN CATCH 
     if @@trancount > 0 
      ROLLBACK TRANSACTION; 
     THROW; 
    END CATCH; 

END; 
+1

Das schützt formal vor dem Fehler Zählen der Übereinstimmung, ist aber im Prinzip falsch. Sie sollten Transaktionen, die Sie nicht gestartet haben, nicht zurücksetzen. Es macht das Schreiben von korrektem Code sehr schwierig, wenn dieser Code Ihren Code aufrufen möchte. – GSerg

0

Der Rollback wird alle Transaktionen zurücksetzen.

Vielleicht könnten Sie Speicherpunkte verwenden.

Als ich kommentierte, könnten Sie @@ TRANCOUNT vor dem Rollback/Commit verwenden, nur um den Fehler loszuwerden, oder "zusammenführen", nicht um Transaktionen selbstständig zu verschachteln.

https://dba.stackexchange.com/questions/82681/how-to-rollback-when-3-stored-procedures-are-started-from-one-stored-procedure/82697

Rollback the inner transaction of nested transaction

Verwandte Themen