如何加入 TransactionScope?

How to enlist with a TransactionScope?

精简版

我如何加入正在进行的 TransactionScope

长版

如果您使用 TransactionScope,您可以创建一个 "ambient" 事务:

using (TransactionScope scope = new TransactionScope())
{
   //...stuff happens, then you complete...

   // The Complete method commits the transaction. 
   scope.Complete();
}

那有什么用?好吧,.NET 框架中有一些 classes 知道如何通过检查 static:

来检查是否有环境正在进行的事务

这让他们知道正在进行交易。

例如,如果您有一些不考虑事务的任意数据库操作:

void DropStudents()
{
   using (var cmd = connection.CreateCommand())
   {
      cmd.CommandText = "DROP TABLE Students;";
      cmd.ExecuteNonQuery();
   }
}

如果你把它放在 TransactionScope 的中间:

using (TransactionScope scope = new TransactionScope())
{
   DropStudents();

   // The Complete method commits the transaction. 
   scope.Complete();
}

突然之间,您的 ADO.net 操作在一个事务中;并且可以回滚。

自动开始事务、提交和回滚

SqlClient库知道要检查:

并在内部自动:

这一切都是魔法。

我该怎么做?

我有一个 class 也有交易。而不是强制调用者调用:

using (IContosoTransaction tx = turboEncabulator.BeginTransaction())
{
   try
   {
      turboEncabulator.UpendCardinalGrammeters();
   }
   catch (Exception ex)
   {
      tx.Rollback();
      throw;
   }
   tx.Commit();
}

如果他们能直接打电话就好了:

turboEncabulator.UpendCardinalGrammeters();

我的代码将简单地检查:

如果有交易正在进行,我会:

但是我该怎么做呢?

我如何在正在进行的 TransactionScope 中注册自己以获取这些通知?

其实并没有那么糟糕。

  1. 通过查看是否分配了 System.Transactions.Transaction.Current 来检查是否有正在进行的交易。如果有,交易中Enlist

    //Enlist in any current transactionScope if one is active
    if (System.Transactions.Transaction.Current != null)
       System.Transactions.Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
    
  2. 然后需要实现IEnlistmentNotification的四个通知方法:

    • void Prepare(PreparingEnlistment preparingEnlistment);
    • void Commit(Enlistment enlistment);
    • void InDoubt(Enlistment enlistment);
    • void Rollback(Enlistment enlistment);

实际实现是简单的样板通知:

  • 准备:事务管理器正在征求您对事务是否适合提交的投票:
    • 投票preparingEnlistment.Prepared();
    • 投票preparingEnlistment.ForceRollback();
  • 提交:尽你所能提交并声明你已完成入伍:
    • enlistment.Done();
  • InDoubt:通知事务管理器与事务中涉及的其他人失去联系。通过让他们知道您已完成入伍来回应:
    • enlistment.Done();
  • Rollback:事务正在回滚的通知。做任何类型的回滚工作,让他们知道你已经完成了入伍:
    • enlistment.Done();

或更完整

public void Prepare(PreparingEnlistment preparingEnlistment)
{
   //The transaction manager is asking for our vote if the transaction
   //can be committed

   //Vote "yes" by calling .Prepared:
   preparingenlistment.Prepared();

   //Vote "no" by calling .ForceRollback:
   //preparingEnlistment.ForceRollback();
}

public void Commit(Enlistment enlistment)
{
   //The transaction is being committed - do whatever it is we do to commit.

   //Let them know we're done with the enlistment.
   enlistment.Done();
}

public void InDoubt(Enlistment enlistment)
{
   //Do any work necessary when indoubt notification is received.
   //This method is called if the transaction manager loses contact with one or more participants, 
   //so their status is unknown.
   //If this occurs, you should log this fact so that you can investigate later whether any of the 
   //transaction participants has been left in an inconsistent state.

   //Let them know we're done with the enlistment.
   enlistment.Done();
}

public void Rollback(Enlistment enlistment)
{
   //If any resource manager reported a failure to prepare in phase 1, the transaction manager invokes 
   //the Rollback method for each resource manager and indicates to the application the failure of the commit.

   //Let them know we're done with the enlistment.
   enlistment.Done();
}