如何加入 TransactionScope?

Posted

技术标签:

【中文标题】如何加入 TransactionScope?【英文标题】:How to enlist with a TransactionScope? 【发布时间】:2021-12-24 21:07:12 【问题描述】:

短版

我如何加入正在进行的TransactionScope

加长版

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

using (TransactionScope scope = new TransactionScope())

   //...stuff happens, then you complete...

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

这有什么用?嗯,.NET 框架中有一些类知道如何通过检查static 来检查是否存在环境正在进行的事务:

System.Transactions.Current

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

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

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 操作在一个事务中;并且可以回滚。

自动 BeginTransaction、提交和回滚

SqlClient 库知道要检查:

System.Transactions.Current

并在内部自动:

开始数据库事务 调用 Scope.Complete 时提交数据库事务 回滚作用域时回滚数据库事务

这一切都只是魔法。

不知何故,DbConnection 收到了呼叫.Commit 的通知 不知何故,DbConnection 收到了呼叫.Rollback 的通知

我该怎么做?

我有一个类也有事务。而不是强迫调用者调用:

using (IContosoTransaction tx = turboEncabulator.BeginTransaction())

   try
   
      turboEncabulator.UpendCardinalGrammeters();
   
   catch (Exception ex)
   
      tx.Rollback();
      throw;
   
   tx.Commit();

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

turboEncabulator.UpendCardinalGrammeters();

我的代码将简单地检查:

System.Transactions.Current

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

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

但是我该怎么做呢?

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

【问题讨论】:

Transaction.Current.TransactionCompleted += (sender, eventArgs) => ...? @GuruStron Transaction.Current.TransactionRolledBack? 【参考方案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);
    

    然后需要实现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(); 回滚:事务正在回滚的通知。做任何形式的回滚工作,让他们知道你已经完成了入伍: 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();

【讨论】:

以上是关于如何加入 TransactionScope?的主要内容,如果未能解决你的问题,请参考以下文章

Transactionscope .net 核心 2

TransactionScope 是如何工作的?

TransactionScope 如何回滚事务?

如何在多实例应用程序上处理 TransactionScope?

忽略特定查询的 TransactionScope

如何在 .NET 4.0 中使用 Microsoft.Bcl.Async 支持 TransactionScope 中的异步方法? [复制]