Freigeben über


Zugriff auf die aktuelle Transaktion

Wenn zu dem Zeitpunkt eine Transaktion aktiv ist, zu dem mit der Ausführung von in SQL Server auszuführendem CLR-Code begonnen wird, dann wird die Transaktion durch die System.Transactions.Transaction-Klasse verfügbar gemacht. Mit der Transaction.Current-Eigenschaft wird auf die aktuelle Transaktion zugegriffen. In den meisten Fällen ist es nicht notwendig, explizit auf die Transaktion zuzugreifen. Bei Datenbankverbindungen überprüft ADO.NET Transaction.Current automatisch beim Aufruf der Connection.Open-Methode, und trägt die Verbindung automatisch in diese Transaktion ein (sofern für das Schlüsselwort Enlist in der Verbindungszeichenfolge nicht false angegeben wurde).

In den folgenden Szenarien sollten Sie das Transaction-Objekt direkt verwenden:

  • Wenn Sie eine Ressource eintragen möchten, die nicht automatisch eingetragen wird oder die aus irgendeinem Grund während der Initialisierung nicht eingetragen wurde.

  • Wenn Sie eine Ressource explizit in die Transaktion eintragen möchten.

  • Wenn Sie die externe Transaktion aus einer gespeicherten Prozedur oder Funktion heraus beenden möchten. In diesem Fall verwenden Sie TransactionScope. Beispielsweise wird mit dem folgenden Code die aktuelle Transaktion rückgängig gemacht.

    using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
    

Im weiteren Verlauf dieses Themas werden andere Möglichkeiten beschrieben, eine externe Transaktion abzubrechen.

Abbrechen einer externen Transaktion

Sie können externe Transaktionen wie folgt von einer verwalteten Prozedur oder einer Funktion aus abbrechen:

  • Die verwaltete Prozedur oder die Funktion kann in einem Ausgabeparameter einen Wert zurückgeben. Die aufrufende Transact-SQL-Prozedur kann den zurückgegebenen Wert überprüfen und gegebenenfalls ROLLBACK TRANSACTION ausführen.

  • Die verwaltete Prozedur oder die Funktion kann eine benutzerdefinierte Ausnahme auslösen. Die aufrufende Transact-SQL-Prozedur kann die Ausnahme, die von der verwalteten Prozedur oder Funktion ausgelöst wird, in einem try/catch-Block abfangen und ROLLBACK TRANSACTION ausführen.

  • Die verwaltete Prozedur oder die Funktion kann die aktuelle Transaktion durch einen Aufruf der Transaction.Rollback-Methode abbrechen, wenn eine bestimmte Bedingung erfüllt wird.

Beim Aufruf innerhalb einer verwalteten Prozedur oder Funktion löst die Transaction.Rollback-Methode eine Ausnahme mit einer nicht eindeutigen Fehlermeldung aus und kann in einen try/catch-Block eingebunden werden. Die Fehlermeldung lautet wie folgt oder ähnlich:

Msg 3994, Level 16, State 1, Procedure uspRollbackFromProc, Line 0
Transaction is not allowed to roll back inside a user defined routine, trigger or aggregate because the transaction is not started in that CLR level. Change application logic to enforce strict transaction nesting.

Diese Ausnahme wird erwartet, und der try/catch-Block ist notwendig, damit die Codeausführung fortgesetzt wird. Wenn kein try/catch-Block vorhanden ist, wird die Ausnahme sofort der aufrufenden Transact-SQL-Prozedur übergeben und der verwaltete Code wird zu Ende ausgeführt. Wenn die Ausführung des verwalteten Codes beendet ist, wird eine andere Ausnahme ausgelöst.

Msg 3991, Level 16, State 1, Procedure uspRollbackFromProc, Line 1 
The context transaction which was active before entering user defined routine, trigger or aggregate " uspRollbackFromProc " has been ended inside of it, which is not allowed. Change application logic to enforce strict transaction nesting. The statement has been terminated.

Diese Ausnahme ist ebenfalls zu erwarten, und die Transact-SQL-Anweisung, welche die den Trigger auslösenden Aktion ausführt, muss in einen try/catch-Block eingeschlossen werden, damit die Ausführung fortgesetzt wird. Trotz der zwei ausgelösten Ausnahmen wird ein Rollback für die Transaktion ausgeführt, und für die Änderungen in der Tabelle wird kein Commit ausgeführt.

Beispiel

Im folgenden Beispiel wird von der verwalteten Prozedur für eine Transaktion mit der Transaction.Rollback-Methode ein Rollback für die Transaktion ausgeführt. Beachten Sie den try/catch-Block um die Transaction.Rollback-Methode im verwalteten Code. Das Transact-SQL-Skript erstellt eine Assembly und eine verwaltete gespeicherte Prozedur. Beachten Sie, dass die EXEC uspRollbackFromProc-Anweisung in einen try/catch-Block eingebunden ist, sodass die Ausnahme abgefangen wird, die ausgelöst wird, sobald die Ausführung der verwalteten Prozedur beendet wurde.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Transactions;

public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void uspRollbackFromProc()
{
   using (SqlConnection connection = new SqlConnection(@"context connection=true"))
   {
      // Open the connection.
      connection.Open();

      bool successCondition = true;

      // Success condition is met.
      if (successCondition)
      {
         SqlContext.Pipe.Send("Success condition met in procedure."); 
         // Perform other actions here.
      }
            
      //  Success condition is not met, the transaction will be rolled back.
      else
      {
         SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...");
         try
         {
               // Get the current transaction and roll it back.
               Transaction trans = Transaction.Current;
               trans.Rollback();
         }
         catch (SqlException ex)
         {
            // Catch the expected exception. 
            // This allows the connection to close correctly.                    
         }  
      }

      // Close the connection.
      connection.Close();
   }
}
};
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Transactions

Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub  uspRollbackFromProc ()
   Using connection As New SqlConnection("context connection=true")

   ' Open the connection.
   connection.Open()

   Dim successCondition As Boolean
   successCondition = False

   ' Success condition is met.
   If successCondition Then

      SqlContext.Pipe.Send("Success condition met in procedure.")

      ' Success condition is not met, the transaction will be rolled back.

   Else
      SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...")
      Try
         ' Get the current transaction and roll it back.
         Dim trans As Transaction
         trans = Transaction.Current
         trans.Rollback()

      Catch ex As SqlException
         ' Catch the exception instead of throwing it.  
         ' This allows the connection to close correctly.                    
      End Try

   End If

   ' Close the connection.
   connection.Close()

End Using
End Sub
End Class

Transact-SQL

--Register assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll' 
Go
CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc
Go

-- Execute procedure.
BEGIN TRY
BEGIN TRANSACTION 
-- Perform other actions.
Exec uspRollbackFromProc
-- Perform other actions.
PRINT N'Commiting transaction...'
COMMIT TRANSACTION
END TRY

BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNum, ERROR_MESSAGE() AS ErrorMessage
PRINT N'Exception thrown, rolling back transaction.'
ROLLBACK TRANSACTION
PRINT N'Transaction rolled back.' 
END CATCH
Go

-- Clean up.
DROP Procedure uspRollbackFromProc;
Go
DROP ASSEMBLY TestProcs;
Go

Siehe auch

Konzepte

CLR-Integration und Transaktionen