Share via


Transaktionsbereich

Die TransactionScope-Klasse stellt eine einfache Methode dar, um einen Codeblock als Teil einer Transaktion zu markieren. Ein Transaktionsbereich kann die Umgebungstransaktion auswählen und verwalten. Wenn Sie einen TransactionScope mithilfe der new-Anweisung instanziieren, ermittelt der Transaktions-Manager, an welcher Transaktion teilgenommen werden soll. Wenn keine Ausnahme im Transaktionsbereich auftritt (das heißt, zwischen der Initialisierung des TransactionScope-Objekts und dem Aufrufen seiner Dispose-Methode), kann die Transaktion, an der der Transaktionsbereich beteiligt ist, fortfahren. Wenn im Transaktionsbereich eine Ausnahme auftritt, wird für die Transaktion, an der der Transaktionsbereich beteiligt ist, ein Rollback ausgeführt. Wenn die Anwendung alle Aktionen, die sie in einer Transaktion ausführen will, beendet hat, wird die Complete-Methode ein Mal aufgerufen. Dadurch wird der Transaktions-Manager darüber informiert, dass ein Commit für die Transaktion ausgeführt werden kann. Wird die Complete-Methode nicht aufgerufen, endet die Transaktion. Weitere Informationen über den Transaktionsbereich finden Sie in der MSDN-Dokumentation.

Implementieren des Transaktionsbereichs in .NET Framework

Der System.Transactions-Namespace ist Teil der Versionen 3.0 und 3.5 von Microsoft .NET Framework Version 2.0. Er bietet ein Transaktionsframework, das vollständig in ADO.NET und die SQL Server CDR-Integration (Common Language Runtime) integriert ist. Die System.Transactions.transactionscope-Klasse ändert einen Codeblock in einen transaktionalen Codeblock, indem sie Verbindungen implizit in eine verteilte Transaktion einträgt. Die Complete-Methode kann am Ende des durch TransactionScope markierten Codeblocks aufgerufen werden. Die Transaktion wird nicht fortgesetzt, wenn die Complete-Methode nicht aufgerufen wird, bevor der Aufruf der Dispose-Methode erfolgt. Wenn eine Ausnahme ausgelöst wird, wird die Transaktion als beendet angesehen.

Weitere Informationen finden Sie unter https://msdn2.microsoft.com/en-us/library/ms172070(VS.80)..

Einschränkungen für System.Transactions

Der System.Transactions-Namespace wird nicht von ..NET Compact Framework 2.0 unterstützt. Daher erfolgt die Implementierung nur für das Windows-Desktopbetriebssystem und entspricht .NET Framework 2.0, .NET Framework 3.0 oder .NET Framework 3.5.

Wenn es zu einem Timeout kommt, ruft die System.Transactions-Infrastruktur ein Rollback von einem separaten Thread aus auf. Der Hauptthread erfährt nicht von dem Rollback im separaten Thread. Bei langen Transaktionen kann es zu nicht deterministischem Verhalten und partiellen Commits kommen. Um dies zu verhindern, erhöhen Sie beim Erstellen des Objekts für den Transaktionsbereich dessen Zeitspanne.

In einem Transaktionsbereich kann nur ein SqlCeConnection-Objekt eingetragen werden, und nur dann, wenn nicht bereits ein anderer Transaktions-Manager in den Transaktionsbereich eingetragen ist.

Wenn eine Verbindung außerhalb eines Transaktionsbereichs geöffnet wird und in einem bestehenden Transaktionsbereich eingetragen werden muss, kann dies anhand der EnlistTransaction-Methode getan werden.

TransactionScope-Implementierung

SQL Server Compact 3.5 trägt eine Ressource in die System.Transactions-Infrastruktur ein.

Wenn mehrere Befehle für die in einen Transaktionsbereich eingetragene Verbindung geöffnet werden, werden sie standardmäßig in den aktuellen Transaktionskontext eingetragen. Es ist zudem möglich, eine Verbindung zu öffnen, die nicht in einen Transaktionsbereich eingetragen ist. Dadurch werden nicht eingetragene Befehle erstellt. Der Standardtransaktionstyp kann für SQL Server Compact 3.5-Transaktionen mit einem Transaktionsbereich serialisiert werden.

Da verteilte Transaktionen nicht von SQL Server Compact 3.5 unterstützt werden, können zwei oder mehr Verbindungen nicht in denselben Transaktionsbereich oder einen geschachtelten Transaktionsbereich, der denselben Umgebungstransaktionsbereich verwendet, eingetragen werden.

Eine explizite Transaktion für eine eingetragene Verbindung innerhalb eines Transaktionsbereichs ist nicht zulässig.

Das implizite Eintragen von Verbindungen wird nicht unterstützt. Um eine Eintragung in einem Transaktionsbereich vorzunehmen, gehen Sie folgendermaßen vor:

  • Öffnen Sie eine Verbindung in einem Transaktionsbereich.
  • Oder, wenn die Verbindung bereits geöffnet ist, rufen Sie die EnlistTransaction-Methode für das Verbindungsobjekt auf.

Einschränkungen von SQL Server Compact

Die Unterschiede zwischen SQL Server Compact 3.5 und SQL Server in Bezug auf den Transaktionsbereich sind folgende:

  • Verteilte Transaktionen werden in SQL Server Compact 3.5 nicht unterstützt. Daher wird eine lokale Transaktion nicht automatisch in eine vollständig verteilbare Transaktion heraufgestuft.
  • Parallele Transaktionen werden von SQL Server Compact 3.5 unterstützt, selbst für mehrere aktive Resultsets, jedoch werden parallele Transaktionen von SQL Server nicht unterstützt.

TransactionScope – Beispiel 1

Das folgende Beispiel zeigt, wie TransactionScope zum Eintragen einer Transaktion und anschließend zur Durchführung eines Commit verwendet wird.

using (TransactionScope transScope = new TransactionScope())

{

using (SqlCeConnection connection1 = new

SqlCeConnection(connectString1))

{

/* Opening connection1 automatically enlists it in the

TransactionScope as a lightweight transaction. */

connection1.Open();

// Do work in the connection.

}

// The Complete method commits the transaction.

transScope.Complete();

}

TransactionScope – Beispiel 2

Im folgenden Codebeispiel wird gezeigt, wie mithilfe von TransactionScope zwei Tabellen in der Datenbank erstellt werden können.

static void Setup(String strDbPath)

{

/* Delete the database file if it already exists. We will create a new one. */

if (File.Exists(strDbPath))

{

File.Delete(strDbPath);

}

// Create a new database.

SqlCeEngine engine = new SqlCeEngine();

engine.LocalConnectionString = @"Data source = " + strDbPath;

engine.CreateDatabase();

engine.Dispose();

}

/* This function creates two tables in the specified database. Before creating the tables, it re-creates the database.

These tables are created in a TransactionScope, which means that either both of them will be created or not created at all. */

static void CreateTablesInTransaction(String strDbPath)

{

/* Create the connection string. In order to have the connection enlisted into the TransactionScope, the Enlist property in the connection string must be explicitly set to true. */

String strConn = @"Data source = " + strDbPath + ";Enlist=true";

SqlCeConnection conn = new SqlCeConnection(strConn);

try

{

Setup(strDbPath); // Create a new database for our tables.

using (TransactionScope scope = new TransactionScope())

{

/* To enlist a connection into a TransactinScope, specify 'Enlist=true' in its connection string and open the connection in the scope of that TransactionScope object. */

conn.Open();

// Create the tables.

SqlCeCommand command = conn.CreateCommand();

command.CommandText = @"create table t1(col1 int)";

command.ExecuteNonQuery();

command.CommandText = @"create table t2(col1 int)";

command.ExecuteNonQuery();

/* If this statement is executed and the TransactionScope has not timed out, t1 and t2 will be created in the specified database. */

scope.Complete();

}

}

catch (SqlCeException e)

{

Console.WriteLine(e.Message);

}

finally

{

if (conn.State != System.Data.ConnectionState.Closed)

{

conn.Close();

}

conn.Dispose();

}

}

TransactionScope – Beispiel 3

Das folgende Beispiel zeigt, wie Werte in zwei Tabellen in einem Transaktionsbereich eingefügt werden.

/* This function assumes that tables t1(col1 int) and t2(col1 int) are already created in the specified database. The condition for the following function is this:

If INSERTs into the first table succeed, then INSERT into the second table. However, if the INSERTs into the second table fail, roll back the inserts in the second table but do not roll back the inserts in the first table. Although this can also be done by way of regular transactions, this function demonstrates how to do it using TransactionScope objects. */

static void CreateTableAndInsertValues(String strDbPath)

{

/* Create the connection string. To have the connection enlisted into the TransactionScope, the Enlist property in the connection string must be explicitly set to true. */

String strConn = @"Data source = " + strDbPath + ";Enlist=true";

SqlCeConnection conn1 = new SqlCeConnection(strConn);

SqlCeConnection conn2 = new SqlCeConnection(strConn);

try

{

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))

{

conn1.Open();

SqlCeCommand command1 = conn1.CreateCommand();

command1.CommandText = @"insert into t1(col1) values(1)";

command1.ExecuteNonQuery();

command1.CommandText = @"insert into t1(col1) values(2)";

command1.ExecuteNonQuery();

/* If this statement is executed and the TransactionScope has not timed out, two records will be inserted into table 1. */

scope.Complete();

try

{

using (TransactionScope scopeInner = new TransactionScope(TransactionScopeOption.RequiresNew))

{

conn2.Open();

SqlCeCommand command2 = conn2.CreateCommand();

command2.CommandText = @"insert into t2(col1) values(1)";

command2.ExecuteNonQuery();

command2.CommandText = @"insert into t2(col1) values(2)";

command2.ExecuteNonQuery();

/* If this statement is run and the TransactionScope has not timed out, two records will be inserted into table 2. */

scopeInner.Complete();

}

}

catch (SqlCeException e)

{

Console.WriteLine(@"Exception in Inner block: " + e.Message);

}

}

}

catch (SqlCeException e)

{

Console.WriteLine(@"Exception in Outer block: " + e.Message);

}

finally

{

// Close both the connections.

if (conn1.State != System.Data.ConnectionState.Closed)

{

conn1.Close();

}

if (conn2.State != System.Data.ConnectionState.Closed)

{

conn2.Close();

}

conn1.Dispose();

conn2.Dispose();

}

}