Udostępnij za pośrednictwem


Implementowanie transakcji jawnej przy użyciu CommitableTransaction

Klasa CommittableTransaction zapewnia jawny sposób używania transakcji przez aplikacje, w przeciwieństwie do niejawnego używania TransactionScope klasy. Jest to przydatne w przypadku aplikacji, które chcą używać tej samej transakcji w wielu wywołaniach funkcji lub wielu wywołań wątków. TransactionScope W przeciwieństwie do klasy moduł zapisywania aplikacji musi w szczególności wywoływać Commit metody i Rollback w celu zatwierdzenia lub przerwania transakcji.

Przegląd klasy CommittableTransaction

CommittableTransaction Klasa pochodzi z Transaction klasy, dlatego dostarczanie wszystkich funkcji drugiego. Jest szczególnie przydatna Rollback metody w Transaction klasa, która umożliwia także wycofać CommittableTransaction obiektu.

Klasa jest podobna Transaction do CommittableTransaction klasy, ale nie oferuje Commit metody. Umożliwia to przekazania obiektu transakcji (lub klony jego) do innych metod (potencjalnie na inny wątek) przy zachowaniu kontroli nad kiedy transakcja została zatwierdzona. Dzwonić kodu jest w stanie zarejestrować i oddawać głosy na transakcji, ale tylko twórca CommittableTransaction obiekt ma możliwość zatwierdzania transakcji.

Należy zwrócić uwagę następujących typów podczas pracy z CommittableTransaction klasy,

  • Tworzenie CommittableTransaction transakcji nie ustawiono otoczenia transakcji. Należy w szczególności wartości i zresetować otoczenia transakcji, aby upewnić się, że menedżerów zasobów działają w kontekście transakcji po prawej, w razie potrzeby. Jest sposobem ustawienia bieżącej transakcji otoczenia przez ustawienie statycznego Current dla właściwości globalnym Transaction obiektu.

  • Element CommittableTransaction obiektu nie może być używany ponownie. Po CommittableTransaction obiektu została przekazana lub wycofana, nie może być używana ponownie w transakcji. Oznacza to, że nie można ustawić jako bieżący kontekst transakcji otoczenia.

Tworzenie CommittableTransaction

Poniższy przykład tworzy nową CommittableTransaction i zatwierdza ją.

//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

Utworzenie wystąpienia CommittableTransaction automatycznie nie ustawiono kontekstu otoczenia transakcji. Dlatego żadnych operacji na Menedżera zasobów nie jest częścią tej transakcji. Właściwość statyczna Current obiektu globalnego Transaction służy do ustawiania lub pobierania transakcji otoczenia, a aplikacja musi ją ręcznie ustawić, aby upewnić się, że menedżerowie zasobów mogą uczestniczyć w transakcji. Istnieje również dobrze jest zapisać stary transakcji otoczenia i go przywrócić po zakończeniu za pomocą CommittableTransaction obiektu.

Aby zatwierdzić transakcję, należy jawnie wywołać metodę Commit . Dla wycofywania transakcji, należy wywołać Rollback metody. Należy zauważyć, że do CommittableTransaction została przekazana lub wycofana, wszystkie zasoby zaangażowane w tej transakcji nadal jest zablokowany.

Element CommittableTransaction obiektu można stosować w przypadku wywołania funkcji i wątków. Jednak deweloper aplikacji musi obsługiwać wyjątki, a w szczególności wywoływać Rollback(Exception) metodę w przypadku awarii.

Zatwierdzanie asynchroniczne

CommittableTransaction Klasa zawiera także mechanizm asynchronicznie Zatwierdzanie transakcji. Zatwierdzenie transakcji może zająć dużo czasu, ponieważ może obejmować wiele dostępu do bazy danych i możliwe opóźnienie sieci. Jeśli chcesz uniknąć zakleszczenia w aplikacjach o wysokiej przepływności, możesz użyć asynchronicznego zatwierdzenia, aby zakończyć pracę transakcyjną tak szybko, jak to możliwe, i uruchomić operację zatwierdzania jako zadanie w tle. BeginCommit i EndCommit metody CommittableTransaction klasy pozwalają w tym celu.

Można wywołać metodę BeginCommit wysłania Napad zatwierdzania do wątków z puli wątków. Można również wywołać EndCommit do określenia, czy transakcja faktycznie została zatwierdzona. Jeśli nie można przekazać z jakiegokolwiek powodu, transakcji EndCommit zgłasza wyjątek transakcji. Jeśli transakcja nie jest jeszcze przekazano do czasu EndCommit jest wywoływana, obiekt wywołujący zostało zablokowane do chwili transakcji nie zostanie przekazana lub zostało przerwane.

Najprostszym sposobem czy asynchroniczne zatwierdzania jest dostarczając metodę wywołania zwrotnego wywoływana, gdy zatwierdzania zostało zakończone. Jednakże, należy wywołać EndCommit metody w oryginalnym CommittableTransaction obiekt używany do wywoływania połączenie. Aby uzyskać ten obiekt, można obniżyć emisję parametru IAsyncResult metody wywołania zwrotnego, ponieważ CommittableTransaction klasa implementuje klasę IAsyncResult .

W poniższym przykładzie pokazano, jak można wykonać zatwierdzenie asynchroniczne.

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  
     }  
}  

Zobacz też