如何加入 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
来检查是否存在环境正在进行的事务:
这让他们知道有一笔交易正在进行中。
例如,如果您有一些不考虑事务的任意数据库操作:
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 4.0 中使用 Microsoft.Bcl.Async 支持 TransactionScope 中的异步方法? [复制]