Condividi tramite


Ambito di una transazione

La classe TransactionScope consente di contrassegnare in modo semplice un blocco di codice come partecipante a una transazione. L'ambito di una transazione consente di selezionare e gestire automaticamente la transazione di ambiente. Quando si crea un'istanza di TransactionScope utilizzando l'istruzione new, il gestore delle transazioni determina la transazione a cui prendere parte. Se non si verifica alcuna eccezione nell'ambito della transazione, ovvero tra l'inizializzazione dell'oggetto TransactionScope e la chiamata al metodo Dispose relativo, la transazione a cui l'ambito prende parte può continuare. Se si verifica un'eccezione nell'ambito della transazione, verrà eseguito il rollback della transazione a cui l'ambito prende parte. Quando l'applicazione ha terminato le operazioni da eseguire in una transazione, il metodo Complete viene chiamato una volta per indicare al gestore delle transazioni che è possibile eseguire il commit della transazione. Se non si esegue alcuna chiamata al metodo Complete, la transazione termina. Per ulteriori informazioni sull'ambito di una transazione, vedere la documentazione di MSDN.

Implementazione dell'ambito di una transazione in .NET Framework

Lo spazio dei nomi System.Transactions fa parte di Microsoft .NET Framework versione 2.0, versioni 3.0, 3.5 e 4, e consente di utilizzare un framework di transazioni completamente integrato con ADO.NET e con l'integrazione di Common Language Runtime (CLR) di SQL Server. La classe System.Transactions.transactionscope crea un blocco di codice transazionale inserendo in modo implicito connessioni in una transazione distribuita. Il metodo Complete può essere chiamato al termine del blocco di codice contrassegnato dalla classe TransactionScope. Se il metodo Complete non viene chiamato prima che venga eseguita una chiamata al metodo Dispose, la transazione viene interrotta. Se viene generata un'eccezione, la transazione viene considerata interrotta.

Per ulteriori informazioni, vedere il sito Web all'indirizzo https://msdn2.microsoft.com/en-us/library/ms172070(VS.80).aspx.

Limiti di System.Transactions

Poiché lo spazio dei nomi System.Transactions non è supportato da .NET Compact Framework 2.0, l'implementazione potrà essere eseguita esclusivamente per sistemi operativi desktop Windows e corrisponderà a .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5 o .NET Framework 4.

Si noti che se si verifica un timeout, l'infrastruttura di System.Transactions chiamerà il metodo Rollback da un thread separato e il thread principale ignorerà il rollback eseguito nel thread separato. Nel caso di transazioni lunghe, il comportamento potrebbe sembrare non deterministico e l'esecuzione del commit potrebbe sembrare parziale. Per risolvere questo problema, aumentare l'intervallo di tempo relativo all'oggetto TransactionScope nel momento in cui viene creato.

Nell'ambito di una transazione è possibile inserire solo un oggetto SqlCeConnection se nell'ambito non è già inserito un gestore delle transazioni.

Se una connessione da inserire nell'ambito di una transazione esistente viene aperta all'esterno dell'ambito, l'inserimento può essere eseguito mediante il metodo EnlistTransaction.

Implementazione di TransactionScope

SQL Server Compact esegue l'inserimento come una risorsa nell'infrastruttura di System.Transactions.

Per impostazione predefinita, l'apertura di più comandi nella connessione inserita nell'ambito di una transazione ne determina l'inserimento nel contesto della transazione corrente. È inoltre possibile aprire una connessione non inserita nell'ambito di una transazione. In questo modo vengono creati comandi non inseriti. Per transazioni di SQL Server Compact a cui è associato un ambito, il tipo di transazione predefinito è Serializable.

Poiché le transazioni distribuite non sono supportate da SQL Server Compact, non è possibile inserire due o più connessioni nello stesso ambito di una transazione oppure nell'ambito di una transazione nidificata che condivide lo stesso ambito di transazione di ambiente.

Non è possibile utilizzare una transazione esplicita per una connessione inserita nell'ambito di una transazione.

L'inserimento esplicito di connessioni non è supportato. Per inserire una connessione nell'ambito di una transazione, è possibile eseguire le operazioni seguenti:

  • Aprire una connessione nell'ambito di una transazione.

  • In alternativa, se la connessione è già aperta, chiamare il metodo EnlistTransaction sull'oggetto connessione.

Limiti di SQL Server Compact

Le differenze tra SQL Server Compact e SQL Server relative all'ambito di una transazione sono le seguenti:

  • In SQL Server Compact le transazioni distribuite non sono supportate, pertanto una transazione locale non verrà promossa automaticamente a una transazione completamente distribuibile.

  • In SQL Server Compact le transazioni parallele sono supportate anche per più set di risultati attivi, mentre non sono supportate in SQL Server.

Esempio 1 di TransactionScope

Nell'esempio seguente viene illustrato come utilizzare l'oggetto TransactionScope per eseguire l'inserimento, quindi eseguire il commit della transazione.

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();

}

Esempio 2 di TransactionScope

Nell'esempio seguente viene illustrato come utilizzare l'oggetto TransactionScope per creare due tabelle nel database.

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();

}

}

Esempio 3 di TransactionScope

Nell'esempio seguente viene illustrato l'inserimento di valori in due tabelle in un oggetto TransactionScope.

/* 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();

}

}