語言

使用 CommitableTransaction 實作明確交易

類別 CommittableTransaction 提供明確的方法,讓應用程式使用交易,而不是隱含地使用 TransactionScope 類別。 這對於想要跨多個函數調用或多個線程呼叫使用相同的交易的應用程式很有用。 不同於 類別 TransactionScope ,應用程式寫入器必須特別呼叫 Commit 和 Rollback 方法,才能認可或中止交易。

CommitableTransaction 類別的概觀

類別 CommittableTransaction 衍生自 Transaction 類別,因此提供後者的所有功能。 特別有用的是 Rollback 類別上的 Transaction 方法,也可用來復原 CommittableTransaction 物件。

類別 Transaction 類似於類別 CommittableTransaction,但不提供 Commit 方法。 這可讓您將交易物件(或其複製品)傳遞給其他方法(可能在其他執行緒上),同時仍控制何時提交交易。 呼叫的程式代碼能夠加入交易並參與投票,但只有物件的建立者 CommittableTransaction 能夠提交交易。

使用CommittableTransaction類別時,您應該注意下列事項:

  • 建立 CommittableTransaction 交易並不會設定環境交易。 您必須特別設定及重設環境交易,以確保資源管理員在適當的交易內容下運作。 設定目前環境交易的方式是在全域Current對象上設定靜態Transaction屬性。

  • 無法重複使用CommittableTransaction物件。 一旦 CommittableTransaction 對象被認可或回滾,就不能再在交易中使用它。 也就是說,它無法設定為目前的環境性交易上下文。

建立 CommittableTransaction

下列範例會建立新的 CommittableTransaction 並提交它。

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

建立的 CommittableTransaction 實例不會自動設定環境交易內容。 因此,資源管理員上的任何作業都不屬於該交易的一部分。 全域Current物件上的靜態Transaction屬性是用來設定或擷取環境交易,而且應用程式必須手動設定它,以確保資源管理員可以參與交易。 當您完成使用 CommittableTransaction 物件時,儲存舊的環境交易並還原它也是一個很好的做法。

若要認可交易,您必須明確呼叫 Commit 方法。 若要回復交易,您應該呼叫 Rollback 方法。 請務必注意,直到 CommittableTransaction 被認可或回滾之前,該交易所涉及的所有資源仍然會被鎖定。

CommittableTransaction物件可以跨函數調用和線程使用。 不過,應用程式開發人員必須處理例外狀況,並在發生失敗時特別呼叫 Rollback(Exception) 方法。

異步提交

類別 CommittableTransaction 也提供以異步方式認可交易的機制。 交易提交可能需要較長時間,因為它可能涉及多個數據庫存取和可能的網路延遲。 當您想要避免高吞吐量應用程式中的死結時,您可以使用異步提交來儘快完成交易工作,並將提交操作作為背景任務執行。 類別BeginCommit的 EndCommit 和 CommittableTransaction 方法可讓您這樣做。

您可以呼叫 BeginCommit ,將認可保留分派至線程集區中的線程。 您也可以呼叫 EndCommit 來判斷交易是否已實際認可。 如果交易因為任何原因而無法認可, EndCommit 則會引發交易例外狀況。 如果在呼叫時 EndCommit 尚未認可交易,呼叫就會被封鎖,直到交易被認可或中止為止。

若要執行異步認可,最簡單的方式是提供一個回呼方法,當認可完成時進行呼叫。 不過,您必須在用來叫用呼叫的原始EndCommit物件上呼叫 CommittableTransaction 方法。 若要取得該物件,您可以向下轉換回呼方法的 IAsyncResult 參數,因為 CommittableTransaction 類別會實作 IAsyncResult 類別。

下列範例示範如何進行異步提交。

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

另請參閱