如何加入 TransactionScope?

Ian*_*oyd 6 .net transactionscope

简洁版本

我如何加入正在进行的TransactionScope

长版

如果您使用TransactionScope,您可以创建一个“环境”事务:

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

   // The Complete method commits the transaction. 
   scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

那有什么用呢?好吧,.NET 框架中有一些类知道如何通过检查以下内容来检查是否存在环境正在进行的事务static

这让他们知道有一项交易正在进行中。

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

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

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

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

   // The Complete method commits the transaction. 
   scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

突然间,您的 ADO.net 操作处于事务中;并且可以回滚。

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

SqlClient库知道要检查:

  • 系统.交易.当前

并自动在内部:

  • 开始数据库事务
  • 调用Scope.Complete时提交数据库事务
  • 回滚范围时回滚数据库事务

这一切都只是魔法。

  • 不知何故,他们DbConnection收到了打电话的通知.Commit
  • 并且以某种方式DbConnection收到通知.Rollback

我怎么做?

我有一堂课也有交易。而不是强迫调用者调用:

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

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

turboEncabulator.UpendCardinalGrammeters();
Run Code Online (Sandbox Code Playgroud)

我的代码将简单地检查:

  • 系统.交易.当前

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

  • 开始交易
  • 等待提交通知
  • 或者等待回滚通知

但我该怎么做呢?

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

Ian*_*oyd 8

其实没那么糟糕。

  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);
    
    Run Code Online (Sandbox Code Playgroud)

    我传递this, 作为将通过它必须实现的接口获取通知回调的对象IEnlistmentNotification

  2. 然后你需要实现以下四种通知方法IEnlistmentNotification

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

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

  • 准备:事务管理器要求您投票决定事务是否适合提交:
    • 投票Yes:致电preparingEnlistment.Prepared();
    • 投票No:致电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();
}
Run Code Online (Sandbox Code Playgroud)