Implementace explicitní transakce přes CommittableTransaction

CommittableTransaction Třída poskytuje explicitní způsob pro použití transakcí, na rozdíl od použití aplikacemi TransactionScope třídy implicitně. Je užitečné pro aplikace, které chcete použít stejnou transakci napříč několika volání funkce nebo více vláken volání. Na rozdíl od TransactionScope třídy pro zápis do aplikace potřebuje konkrétně volat Commit a Rollback metody za účelem potvrzení nebo přerušení transakce.

Přehled třídy CommittableTransaction

CommittableTransaction Třída odvozena z Transaction třídy, proto poskytuje všechny funkce ten. Je obzvláště užitečná Rollback metodu na Transaction třídu, která lze také použít k vrácení zpět CommittableTransaction objektu.

Třída Transaction je podobná CommittableTransaction třídě, ale nenabízí metodu Commit . To umožňuje předat objekt transakce (nebo klony jeho) do jiné metody (potenciálně na jiných vláknech) při stále řízení při transakce se potvrzeny. Je volána kód je možné zařazení a hlasovat pro transakce, ale pouze tvůrce CommittableTransaction objektu má možnost potvrzení transakce.

Všimněte si těchto hodnot při práci s CommittableTransaction třídy

  • Vytváření CommittableTransaction transakce nenastaví okolí transakce. Je třeba konkrétně nastavena a okolí transakce, ujistěte se, že správci prostředků pracovat v kontextu vpravo transakce v případě potřeby obnovit. Způsob, jak nastavit aktuální okolí transakce je nastavením statické Current vlastnost na globální Transaction objektu.

  • Objekt CommittableTransaction objektu nelze znovu použít. Jednou CommittableTransaction objektu byla potvrzena nebo vrácena zpět, nelze jej použít znovu v transakci. To znamená nelze jej nastavit jako aktuální kontext okolí transakce.

Vytváření CommittableTransaction

Následující příklad vytvoří nový CommittableTransaction a potvrdí ji.

//Create a committable transaction
tx = new CommittableTransaction();

SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind");
SqlCommand myCommand = new SqlCommand();

//Open the SQL connection
myConnection.Open();

//Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx);

myCommand.Connection = myConnection;

// Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
myCommand.ExecuteNonQuery();

// Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
myCommand.ExecuteNonQuery();

// Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
myCommand.ExecuteNonQuery();

// Commit or rollback the transaction
while (true)
{
    Console.Write("Commit or Rollback? [C|R] ");
    ConsoleKeyInfo c = Console.ReadKey();
    Console.WriteLine();

    if ((c.KeyChar == 'C') || (c.KeyChar == 'c'))
    {
        tx.Commit();
        break;
    }
    else if ((c.KeyChar == 'R') || (c.KeyChar == 'r'))
    {
        tx.Rollback();
        break;
    }
}
myConnection.Close();
tx = null;
tx = New CommittableTransaction

Dim myConnection As New SqlConnection("server=(local)\SQLExpress;Integrated Security=SSPI;database=northwind")
Dim myCommand As New SqlCommand()

'Open the SQL connection
myConnection.Open()

'Give the transaction to SQL to enlist with
myConnection.EnlistTransaction(tx)

myCommand.Connection = myConnection

'Restore database to near it's original condition so sample will work correctly.
myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)"
myCommand.ExecuteNonQuery()

'Insert the first record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')"
myCommand.ExecuteNonQuery()

'Insert the second record.
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')"
myCommand.ExecuteNonQuery()

'Commit or rollback the transaction
Dim c As ConsoleKeyInfo
While (True)
    Console.Write("Commit or Rollback? [C|R] ")
    c = Console.ReadKey()
    Console.WriteLine()

    If (c.KeyChar = "C") Or (c.KeyChar = "c") Then
        tx.Commit()
        Exit While
    ElseIf ((c.KeyChar = "R") Or (c.KeyChar = "r")) Then
        tx.Rollback()
        Exit While
    End If
End While

myConnection.Close()
tx = Nothing

Vytváření instance CommittableTransaction automaticky nenastaví kontext okolí transakce. Proto všechny operace na správce prostředků není součástí této transakce. Statické Current vlastnost na globální Transaction objektu se používá k nastavení nebo načtení okolí transakce a aplikace musíte ručně nastavit k zajištění správci prostředků mohou být součástí transakce. Je také vhodné k uložení původní okolí transakce a jeho obnovení po dokončení práce CommittableTransaction objektu.

Potvrzení transakce, je třeba explicitně volat Commit metody. Pro vrácení zpět transakcí, měli byste zavolat Rollback metody. Je důležité si všimněte si, že až CommittableTransaction byl potvrzené nebo vrátit zpět všechny prostředky zahrnuté v tom, že transakce jsou stále uzamčena.

Objekt CommittableTransaction objekt lze použít v rámci volání funkce a vlákna. Je však až do vývojář aplikace ke zpracování výjimek a konkrétně volání Rollback(Exception) metodu v případě selhání.

Asynchronní zápis

CommittableTransaction Třída rovněž poskytuje mechanismus pro potvrzení transakce asynchronně. Zápis transakce může trvat značné množství času, jak ji může zahrnovat více přístup k databázi a latence možný sítě. Pokud chcete, aby se zabránilo zablokování v vysoce výkonných aplikací, můžete pomocí asynchronní zápis dokončete transakční pracovní co nejdříve a spustit operaci potvrzení jako pozadí úlohu. BeginCommit a EndCommit metody CommittableTransaction třída umožňuje provést.

Můžete volat BeginCommit odesláním holdup potvrzení na vlákno z fondu podprocesů. Můžete také volat EndCommit k určení, pokud transakce ve skutečnosti byla. Je-li transakce se nepodařilo zapsat z jakéhokoli důvodu EndCommit vyvolá výjimka transakce. Pokud není v čase ještě potvrzené transakce EndCommit je volána, volajícího bude blokován, dokud nebude transakce potvrzena nebo zrušena.

Nejjednodušší způsob, jak provést asynchronní zápis je poskytnutím metoda zpětného volání, která se má volat po dokončení potvrzení. Je však třeba volat EndCommit metodu na původní CommittableTransaction objekt použitý k vyvolání volání. Chcete-li získat tento objekt, můžete downcast IAsyncResult parametr metody zpětné volání, protože CommittableTransaction třída implementuje IAsyncResult třídu.

Následující příklad ukazuje, jak lze provést asynchronní zápis.

public void DoTransactionalWork()  
{  
     Transaction oldAmbient = Transaction.Current;  
     CommittableTransaction committableTransaction = new CommittableTransaction();  
     Transaction.Current = committableTransaction;  
  
     try  
     {  
          /* Perform transactional work here */  
          // No errors - commit transaction asynchronously  
          committableTransaction.BeginCommit(OnCommitted,null);  
     }  
     finally  
     {  
          //Restore the ambient transaction
          Transaction.Current = oldAmbient;  
     }  
}  
void OnCommitted(IAsyncResult asyncResult)  
{  
     CommittableTransaction committableTransaction;  
     committableTransaction = asyncResult as CommittableTransaction;
     Debug.Assert(committableTransaction != null);  
     try  
     {  
          using(committableTransaction)  
          {  
               committableTransaction.EndCommit(asyncResult);  
          }  
     }  
     catch(TransactionException e)  
     {  
          //Handle the failure to commit  
     }  
}  

Viz také